带有远程网络驱动程序的 CDP。 “WebDriver”对象没有属性“execute_cdp_cmd”python

问题描述 投票:0回答:3

我正在尝试使用 CDP 运行测试,

webdriver.execute_cdp_cmd('Network.enable', {}) 

使用远程网络驱动程序(在 Selenoid 中)。但出现此错误:

AttributeError:“WebDriver”对象没有属性“execute_cdp_cmd”。 在本地环境下效果很好。我尝试过使用 Selenium 3.141.0 和 4.1.3。

我熟悉 PyCDP 文档(https://py-cdp.readthedocs.io/en/latest/getting_started.html),但我不知道如何正确使用它。

为什么它不能与远程网络驱动程序一起使用?有人有在 Selenium 4 中使用 python 执行 CDP 命令的示例吗?

我使用以下功能:

capability = { 'loggingPrefs': {'browser': 'ALL'}, 'goog:loggingPrefs': {'performance': 'ALL'}, "browserName": "chrome", "browserVersion": "99.0", “selenoid:options”: { “enableVNC”: True, “enableVideo”: False } }

如果 request.config.getoption('--remote'): 驱动程序= webdriver.Remote(command_executor ='selenoid.dev:4444 / wd / hub',desired_capability =功能,选项=选项)

python selenium selenium-chromedriver google-chrome-devtools selenoid
3个回答
9
投票

看起来远程 Web 驱动程序不支持 CDP。

找到了这个问题的甜蜜解决方案:

import json

def send(driver, cmd, params={}):
  resource = "/session/%s/chromium/send_command_and_get_result" % driver.session_id
  url = driver.command_executor._url + resource
  body = json.dumps({'cmd': cmd, 'params': params})
  response = driver.command_executor._request('POST', url, body)
  return response.get('value')

send(webdriver, 'Network.enable', {})

相关讨论:https://github.com/SeleniumHQ/selenium/issues/8672


2
投票

2024 年,CDP 似乎正在为远程驱动程序工作。

我的代码示例以及我如何使用它来获取特定的第 3 方 API 调用响应的解决方案:

import json
import logging
import sys

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.remote.webdriver import WebDriver

logging.basicConfig(stream=sys.stdout, level=logging.INFO)
logger = logging.getLogger(__name__)


def prepare_browser() -> WebDriver:
    chrome_options = Options()
    chrome_options.add_argument("--no-sandbox")
    chrome_options.add_argument("--disable-dev-shm-usage")
    chrome_options.add_argument("--window-size=1920,1080")
    chrome_options.add_experimental_option(
        "prefs",
        {
            "intl.accept_languages": "en,en_US",
            "profile.managed_default_content_settings.images": 2,
        },
    )
    chrome_options.set_capability("goog:loggingPrefs", {"performance": "ALL"})
    chrome_options.set_capability("browserVersion", "latest")
    chrome_options.set_capability(
        "selenoid:options", {"enableVNC": True, "enableVideo": False}
    )

    return webdriver.Remote(
        command_executor="http://<selenoid-host>:4444/wd/hub",
        options=chrome_options,
    )


def get_browser_request_body(driver: WebDriver, request_id: str) -> str:
    browser_response = driver.execute(
        driver_command="executeCdpCommand",
        params={
            "cmd": "Network.getResponseBody",
            "params": {"requestId": request_id},
        },
    )
    return browser_response["value"]["body"].split("\n")[-1]


def get_browser_performance_logs(driver: WebDriver) -> list[dict]:
    browser_response = driver.execute(
        driver_command="getLog", params={"type": "performance"}
    )
    return browser_response["value"]


def intercept_json_by_url_part(driver: WebDriver, url_part: str) -> str | None:
    performance_logs = get_browser_performance_logs(driver=driver)

    for log in performance_logs:
        message = log["message"]

        if "Network.response" not in log["message"]:
            continue

        params = json.loads(message)["message"].get("params")
        response = params.get("response") if params else None

        if response and url_part in response["url"]:
            logger.info(f"Found required url part in url: {response['url']}")
            return get_browser_request_body(
                driver=driver, request_id=params["requestId"]
            )


def main() -> None:
    driver = prepare_browser()

    driver.get("https://demo.realworld.io")

    response = intercept_json_by_url_part(driver=driver, url_part="/api/tags")
    print(response)

    """
    Response:
    {"tags":["est","enim","ipsum","repellat","exercitationem","eos","quia","tenetur","facilis","consequatur"]}
    """


if __name__ == "__main__":
    main()

重要提示(2024-03-28):

我上面的代码示例将从 Selenium 4.16.0 开始工作

出于任何原因,如果您想通过 Chrome for Selenium 4.0.0 使用远程连接 < selenium < 4.16.0 you should configure the Remote Connection class for Chrome:

from selenium.webdriver import DesiredCapabilities
from selenium.webdriver.chromium.remote_connection import ChromiumRemoteConnection


class ChromeRemoteConnection(ChromiumRemoteConnection):
    browser_name = DesiredCapabilities.CHROME["browserName"]

    def __init__(
        self,
        remote_server_addr: str,
        keep_alive: bool = True,
        ignore_proxy: bool = False,
    ) -> None:
        super().__init__(
            remote_server_addr=remote_server_addr,
            vendor_prefix="goog",
            browser_name=ChromeRemoteConnection.browser_name,
            keep_alive=keep_alive,
            ignore_proxy=ignore_proxy,
        )


def prepare_browser() -> WebDriver:
    chrome_options = Options()
    chrome_options.add_argument("--no-sandbox")
    chrome_options.add_argument("--disable-dev-shm-usage")
    chrome_options.add_argument("--window-size=1920,1080")
    chrome_options.add_experimental_option(
        "prefs",
        {
            "intl.accept_languages": "en,en_US",
            "profile.managed_default_content_settings.images": 2,
        },
    )
    chrome_options.set_capability("goog:loggingPrefs", {"performance": "ALL"})
    chrome_options.set_capability("browserVersion", "latest")
    chrome_options.set_capability("browserName", "chrome")
    chrome_options.set_capability(
        "selenoid:options", {"enableVNC": True, "enableVideo": False}
    )

    command_executor = ChromeRemoteConnection(
        remote_server_addr="http://<selenoid-host>:4444/wd/hub"
    )
    return webdriver.Remote(
        command_executor=command_executor, options=chrome_options
    )

0
投票

在Python的Selenium库中使用CDP的官方方法是使用双向功能

它是一个异步 API。但是,您可以使用 trio 将其转换为同步 API。我使用包装函数来使其更易于使用。

from selenium import webdriver
# You may need to change this if you need to use different version of CDP
import selenium.webdriver.common.devtools.v111 as devtools
import trio

def execute_cdp(driver: webdriver.Remote, cmd):
    async def execute_cdp_async():
        async with driver.bidi_connection() as session:
            cdp_session = session.session
            return await cdp_session.execute(cmd)
    # It will have error if we use asyncio.run
    # https://github.com/SeleniumHQ/selenium/issues/11244
    return trio.run(execute_cdp_async)

# Use it this way:
execute_cdp(driver, devtools.network.enable())
mhtml = execute_cdp(driver, devtools.page.capture_snapshot())
© www.soinside.com 2019 - 2024. All rights reserved.