python-3.x 如何重新连接到webdriver with selenium打开的浏览器?

1cklez4t  于 2022-11-19  发布在  Python
关注(0)|答案(4)|浏览(169)

由于一些未知的原因,我的浏览器打开远程服务器的测试页面非常慢。所以我想如果我可以在退出脚本后重新连接到浏览器,但不执行webdriver.quit(),这将使浏览器打开。这可能是一种HOOK或webdriver句柄。我已经查找了selenium API文档,但没有找到任何函数。我使用的是Chrome 62,x64,windows 7, selenium 3.8.0。我将非常感谢这个问题是否能得到解决。

xqnpmsa8

xqnpmsa81#

,退出脚本后无法重新连接到以前的 *Web浏览会话 *。即使能够从以前的 * 浏览上下文 * 中提取Session IDCookies和其他会话属性,也无法将这些属性作为 HOOK 传递到WebDriver。

一种更简洁的方法是调用webdriver.quit(),然后跨越一个新的 Browsing Context

深入了解

关于将 WebDriver 重新连接到现有的正在运行的 * 浏览上下文 *,已经有很多讨论和尝试。在讨论Allow webdriver to attach to a running browserSimon Stewart[Creator WebDriver]中明确提到:

  • 重新连接到现有的 * 浏览上下文 * 是浏览器特定的功能,因此不能以通用的方式实现。
  • 使用internet-explorer,可以遍历操作系统中打开的窗口,并找到要连接的正确IE进程。
  • firefoxgoogle-chrome需要在特定的模式和配置下启动,这实际上意味着仅仅连接到一个正在运行的示例在技术上是不可能的。

tl; dr

webdriver.firefox.useExisting not implemented

whhtz7ly

whhtz7ly2#

是的,这其实很容易做到。

selenium <->webdriver会话由连接url和session_id表示,您只需重新连接到现有的会话。

免责声明-该方法使用Selenium内部属性(某种程度上是“私有”),在新版本中可能会发生变化;最好不要将其用于生产代码;最好不要用于远程SE(您的集线器或BrowserStack/酱料之类的提供商),因为最后解释了一个警告/资源流失。

启动webdriver示例时,需要获取上述属性;样品:

from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://www.google.com/')

# now Google is opened, the browser is fully functional; print the two properties
# command_executor._url (it's "private", not for a direct usage), and session_id

print(f'driver.command_executor._url: {driver.command_executor._url}')
print(f'driver.session_id: {driver.session_id}')

现在知道了这两个属性,另一个示例就可以连接了;“诀窍”是启动一个Remote驱动程序,并提供上面的_url-因此它将连接到正在运行的selenium进程:

driver2 = webdriver.Remote(command_executor=the_known_url)  
# when the started selenium is a local one, the url is in the form 'http://127.0.0.1:62526'

运行该程序后,您将看到一个新的浏览器窗口正在打开。
这是因为在启动驱动程序时,selenium库会自动为其启动一个新会话-现在您有一个webdriver进程和两个会话(浏览器示例)。
如果你导航到一个url,你会看到它在新的浏览器示例上执行,而不是在上一个开始后剩下的那个--这不是你想要的行为。
此时,需要完成两件事- a)关闭当前SE会话(“新会话”),以及b)将此示例切换到上一个会话:

if driver2.session_id != the_known_session_id:   # this is pretty much guaranteed to be the case
    driver2.close()   # this closes the session's window - it is currently the only one, thus the session itself will be auto-killed, yet:
    driver2.quit()    # for remote connections (like ours), this deletes the session, but does not stop the SE server

# take the session that's already running
driver2.session_id = the_known_session_id

# do something with the now hijacked session:
driver.get('https://www.bing.com/')

就这样-您现在连接到以前/已经存在的会话,以及它的所有属性(cookie,LocalStorage等)。
顺便说一下,在启动新的远程驱动程序时,您不必提供desired_capabilities-这些驱动程序是从您接管的现有会话中存储和继承的。

警告-运行SE进程可能会导致系统中的一些资源耗尽。

每当一个进程启动后没有关闭时--就像第一段代码一样--它会一直呆在那里,直到你手动杀死它。我的意思是--比如在Windows中--你会看到一个“chromedriver.exe”进程,一旦你完成了它,你就必须手动终止它。它不能被一个连接到它的驱动程序关闭,就像一个远程selenium进程一样。
原因是--无论何时启动一个本地浏览器示例,然后调用它的quit()方法,它都有两个部分--第一个部分是从Selenium示例中删除会话(上面第二段代码中所做的),另一个部分是停止本地服务(chrome/geckodriver)--这通常可以正常工作。
问题是,对于远程会话,缺少第二部分--你的本地机器不能控制远程进程,这是远程集线器的工作。所以第二部分实际上是一个pass python语句--一个no-op。
如果您在远程集线器上启动了太多的selenium服务,并且无法控制它,这将导致该服务器的资源耗尽。BrowserStack等云提供商采取了相应的措施来防止这种情况-他们正在关闭过去60年没有活动的服务,等等-这是您不想做的事情。
至于本地SE服务-只是不要忘记偶尔清理操作系统从孤立的 selenium 驱动程序你忘记了:)

ubof19bj

ubof19bj3#

好的,在混合了这里分享的各种解决方案和调整后,我现在有这个工作,如下所示。脚本将使用以前打开的chrome窗口,如果存在的话-远程连接是完全能够杀死浏览器,如果需要和代码功能刚刚好。
我希望有一种方法来自动获取会话ID和URL为以前的活动会话,而不必写出他们到一个文件在hte以前的会话为回升。
这是我在这里的第一篇文章,所以很抱歉打破了任何规范

#Set manually - read/write from a file for automation
session_id =  "e0137cd71ab49b111f0151c756625d31"
executor_url = "http://localhost:50491"

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
 

remote_session = 0

#Try to connect to the last opened session - if failing open new window
try:
    driver = attach_to_session(executor_url,session_id)
    driver.current_url
    print(" Driver has an active window we have connected to it and running here now : ")
    print(" Chrome session ID ",session_id)
    print(" executor_url",executor_url)

except:
    print("No Driver window open - make a new one")
    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()),options=myoptions)
    session_id = driver.session_id 
    executor_url = driver.command_executor._url
hl0ma9xz

hl0ma9xz4#

不去探究为什么你认为保持浏览器窗口打开就能解决速度慢的问题,你并不真的需要一个句柄来做到这一点。只要继续运行测试,而不关闭会话,或者换句话说,不调用driver.quit(),就像你自己提到的那样。这里的问题是,框架自带了自己的runner?像Cucumber?
在任何情况下,你都必须有一些“设置”和“清理”代码。所以你需要做的是确保在“清理”阶段浏览器回到它的初始状态。这意味着:

  • 显示空白页
  • 清除会话的Cookie

相关问题