Selenium可以与现有的浏览器会话进行交互吗?

Ang*_*ero 66 selenium communication webdriver selenium-webdriver

有人知道Selenium(最好是WebDriver)是否能够在启动Selenium客户端之前与已经运行的浏览器进行通信并采取行动?

我的意思是,如果Selenium能够在不使用Selenium Server的情况下与浏览器通信(例如可以手动启动Internet Explorer).

Man*_*ahu 33

这是一个重复的答案**重新连接到python selenium中的驱动程序**这适用于所有驱动程序和java api.

  1. 打开一个司机

    driver = webdriver.Firefox()  #python
    
    Run Code Online (Sandbox Code Playgroud)
  2. 从驱动程序对象中提取到session_id和_url.

    url = driver.command_executor._url       #"http://127.0.0.1:60622/hub"
    session_id = driver.session_id            #'4e167f26-dc1d-4f51-a207-f761eaf73c31'
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用这两个参数连接到您的驱动程序.

    driver = webdriver.Remote(command_executor=url,desired_capabilities={})
    driver.session_id = session_id
    
    Run Code Online (Sandbox Code Playgroud)

    并且您再次与您的司机联系.

    driver.get("http://www.mrsmart.in")
    
    Run Code Online (Sandbox Code Playgroud)

  • 似乎不再工作了. (6认同)
  • 它适用于我,除了每次重复虚拟浏览器. (3认同)
  • `selenium.common.exceptions.SessionNotCreatedException:消息:会话已启动` (3认同)
  • 我尝试了这个解决方案,但它不起作用,并且出现错误,指出 selenium.common.exceptions.SessionNotCreatedException:消息:会话已启动。 (3认同)
  • 如果您需要关闭虚拟浏览器窗口,只需在更新会话 ID 之前调用“driver.close()”即可。 (2认同)

Rob*_*anu 24

这是一个非常古老的功能请求:允许webdriver连接到正在运行的浏览器.所以它官方不受支持.

但是,有一些工作代码声称支持这个:https://web.archive.org/web/20171214043703/http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/.


Ahm*_*our 22

这里开始,如果手动打开浏览器,则可以使用远程调试:

  1. 启动 Chrome

    chrome --remote-debugging-port=9222
    
    Run Code Online (Sandbox Code Playgroud)

或者使用可选配置文件

chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\selenium\ChromeProfile"
Run Code Online (Sandbox Code Playgroud)
  1. 然后:Java:
chrome --remote-debugging-port=9222
Run Code Online (Sandbox Code Playgroud)

Python:

chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\selenium\ChromeProfile"
Run Code Online (Sandbox Code Playgroud)

  • 被低估了!简单易行的解决方案。我首先遇到一个问题,硒打开了另一个浏览器窗口。我使用 [驱动程序管理器](https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/#1-driver-management-software) 代替 chrome_driver,但我忘记使用 chrome_options 第二个参数。 (4认同)

Pav*_*sov 14

此代码段成功允许重用现有的浏览器实例,同时避免引发重复的浏览器.发现于Tarun Lalwani的博客.

from selenium import webdriver
from selenium.webdriver.remote.webdriver import WebDriver

# executor_url = driver.command_executor._url
# session_id = driver.session_id

def attach_to_session(executor_url, session_id):
    original_execute = WebDriver.execute
    def new_command_execute(self, command, params=None):
        if command == "newSession":
            # Mock the response
            return {'success': 0, 'value': None, 'sessionId': session_id}
        else:
            return original_execute(self, command, params)
    # Patch the function before creating the driver object
    WebDriver.execute = new_command_execute
    driver = webdriver.Remote(command_executor=executor_url, desired_capabilities={})
    driver.session_id = session_id
    # Replace the patched function with original function
    WebDriver.execute = original_execute
    return driver

bro = attach_to_session('http://127.0.0.1:64092', '8de24f3bfbec01ba0d82a7946df1d1c3')
bro.get('http://ya.ru/')
Run Code Online (Sandbox Code Playgroud)

  • @SK我想要手动打开的chrome窗口的会话ID,我没有使用selenium打开该窗口 (6认同)
  • 有没有办法通过自动化找到现有的会话 ID 和执行器 URL?就我而言,另一个应用程序打开了浏览器会话,我想使用它。您能推荐一下如何找到浏览器会话 ID 吗? (2认同)
  • `driver.service.service_url` 也适用于 URL,并且不需要访问受保护的文件。 (2认同)

Ale*_*yin 9

有可能的.但你必须破解它,有一个代码你需要做的是运行独立服务器和"补丁"RemoteWebDriver

public class CustomRemoteWebDriver : RemoteWebDriver
{
    public static bool newSession;
    public static string capPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestFiles", "tmp", "sessionCap");
    public static string sessiodIdPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestFiles", "tmp", "sessionid");

    public CustomRemoteWebDriver(Uri remoteAddress) 
        : base(remoteAddress, new DesiredCapabilities())
    {
    }

    protected override Response Execute(DriverCommand driverCommandToExecute, Dictionary<string, object> parameters)
    {
        if (driverCommandToExecute == DriverCommand.NewSession)
        {
            if (!newSession)
            {
                var capText = File.ReadAllText(capPath);
                var sidText = File.ReadAllText(sessiodIdPath);

                var cap = JsonConvert.DeserializeObject<Dictionary<string, object>>(capText);
                return new Response
                {
                    SessionId = sidText,
                    Value = cap
                };
            }
            else
            {
                var response = base.Execute(driverCommandToExecute, parameters);
                var dictionary = (Dictionary<string, object>) response.Value;
                File.WriteAllText(capPath, JsonConvert.SerializeObject(dictionary));
                File.WriteAllText(sessiodIdPath, response.SessionId);
                return response;
            }
        }
        else
        {
            var response = base.Execute(driverCommandToExecute, parameters);
            return response;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 基于这个出色的解决方案,我写了一篇完整的博客文章,其中我讨论了如何连接已经打开的chrome浏览器实例.该博客文章中还附有完整的源代码.http://binaryclips.com/2015/08/25/selenium-webdriver-in-c-how-to-use-the-existing-window-of-chrome-browser/ (3认同)

Big*_*kin 7

受到 Eric 的回答的启发,这是我在 selenium 3.7.0 中解决这个问题的方法。与http://tarunlalwani.com/post/reusing-existing-browser-session-selenium/的解决方案相比,优点是每次连接到现有会话时都不会出现空白的浏览器窗口。

import warnings

from selenium.common.exceptions import WebDriverException
from selenium.webdriver.remote.errorhandler import ErrorHandler
from selenium.webdriver.remote.file_detector import LocalFileDetector
from selenium.webdriver.remote.mobile import Mobile
from selenium.webdriver.remote.remote_connection import RemoteConnection
from selenium.webdriver.remote.switch_to import SwitchTo
from selenium.webdriver.remote.webdriver import WebDriver


# This webdriver can directly attach to an existing session.
class AttachableWebDriver(WebDriver):
    def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',
                 desired_capabilities=None, browser_profile=None, proxy=None,
                 keep_alive=False, file_detector=None, session_id=None):
        """
        Create a new driver that will issue commands using the wire protocol.

        :Args:
         - command_executor - Either a string representing URL of the remote server or a custom
             remote_connection.RemoteConnection object. Defaults to 'http://127.0.0.1:4444/wd/hub'.
         - desired_capabilities - A dictionary of capabilities to request when
             starting the browser session. Required parameter.
         - browser_profile - A selenium.webdriver.firefox.firefox_profile.FirefoxProfile object.
             Only used if Firefox is requested. Optional.
         - proxy - A selenium.webdriver.common.proxy.Proxy object. The browser session will
             be started with given proxy settings, if possible. Optional.
         - keep_alive - Whether to configure remote_connection.RemoteConnection to use
             HTTP keep-alive. Defaults to False.
         - file_detector - Pass custom file detector object during instantiation. If None,
             then default LocalFileDetector() will be used.
        """
        if desired_capabilities is None:
            raise WebDriverException("Desired Capabilities can't be None")
        if not isinstance(desired_capabilities, dict):
            raise WebDriverException("Desired Capabilities must be a dictionary")
        if proxy is not None:
            warnings.warn("Please use FirefoxOptions to set proxy",
                          DeprecationWarning)
            proxy.add_to_capabilities(desired_capabilities)
        self.command_executor = command_executor
        if type(self.command_executor) is bytes or isinstance(self.command_executor, str):
            self.command_executor = RemoteConnection(command_executor, keep_alive=keep_alive)

        self.command_executor._commands['GET_SESSION'] = ('GET', '/session/$sessionId')  # added

        self._is_remote = True
        self.session_id = session_id  # added
        self.capabilities = {}
        self.error_handler = ErrorHandler()
        self.start_client()
        if browser_profile is not None:
            warnings.warn("Please use FirefoxOptions to set browser profile",
                          DeprecationWarning)

        if session_id:
            self.connect_to_session(desired_capabilities)  # added
        else:
            self.start_session(desired_capabilities, browser_profile)

        self._switch_to = SwitchTo(self)
        self._mobile = Mobile(self)
        self.file_detector = file_detector or LocalFileDetector()

        self.w3c = True  # added hardcoded

    def connect_to_session(self, desired_capabilities):
        response = self.execute('GET_SESSION', {
            'desiredCapabilities': desired_capabilities,
            'sessionId': self.session_id,
        })
        # self.session_id = response['sessionId']
        self.capabilities = response['value']
Run Code Online (Sandbox Code Playgroud)

使用方法:

if use_existing_session:
    browser = AttachableWebDriver(command_executor=('http://%s:4444/wd/hub' % ip),
                                  desired_capabilities=(DesiredCapabilities.INTERNETEXPLORER),
                                  session_id=session_id)
    self.logger.info("Using existing browser with session id {}".format(session_id))
else:
    browser = AttachableWebDriver(command_executor=('http://%s:4444/wd/hub' % ip),
                                  desired_capabilities=(DesiredCapabilities.INTERNETEXPLORER))
    self.logger.info('New session_id  : {}'.format(browser.session_id))
Run Code Online (Sandbox Code Playgroud)