如何重新连接到 webdriver 使用 selenium 打开的浏览器?

新手上路,请多包涵

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

原文由 imbaiye 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
2 个回答

,退出脚本后无法重新连接到之前的 _Web 浏览会话_。即使您能够从先前的 浏览上下文 中提取 Session IDCookies 和其他会话属性,您仍然无法将这些属性作为 HOOK 传递给 WebDriver

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


深潜

已经有很多讨论和尝试将 WebDriver 重新连接到现有的正在运行的 Browsing Context 。在讨论 Allow webdriver to attach to a running browser Simon Stewart [Creator WebDriver] 中明确提到:

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

TL;博士

webdriver.firefox.useExisting 未实现

原文由 undetected Selenium 发布,翻译遵循 CC BY-SA 4.0 许可协议

的,这实际上很容易做到。

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

免责声明- 该方法使用 selenium 内部属性(“私有”,在某种程度上),这可能会在新版本中发生变化;你最好不要将它用于生产代码;最好不要用于远程 SE(你的集线器,或像 BrowserStack/Sauce Labs 这样的提供商),因为最后解释了警告/资源消耗。

启动一个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 库会自动为其启动一个新会话 - 现在您有 1 个 webdriver 进程和 2 个会话(浏览器实例)。

如果你导航到一个 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/')

而且,就是这样 - 您现在连接到以前/已经存在的会话,及其所有属性(cookies、LocalStorage 等)。

顺便说一下,在启动新的远程驱动程序时,您不必提供 desired_capabilities - 这些是从您接管的现有会话中存储和继承的。


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

每当一个启动然后没有关闭 - 就像在第一段代码中一样 - 它会留在那里直到你手动杀死它。我的意思是 - 例如在 Windows 中 - 你会看到一个“chromedriver.exe”进程,你必须在完成后手动终止它。它不能被连接到远程 selenium 进程的驱动程序关闭。

原因 - 每当您启动本地浏览器实例,然后调用它的 quit() 方法时,它有两个部分 - 第一个是从 Selenium 实例中删除会话(第二个代码中做了什么在那里拼凑),另一个是停止本地服务(chrome/geckodriver)——通常工作正常。

问题是,对于远程会话,第二部分丢失了——您的本地机器无法控制远程进程,这是远程集线器的工作。所以第二部分实际上是一个 pass python 语句 - 一个空操作。

如果您在远程集线器上启动了太多的 selenium 服务,并且无法控制它 - 这将导致该服务器的资源流失。像 BrowserStack 这样的云提供商对此采取了措施——他们正在关闭过去 60 年代没有任何活动的服务,等等——但这是你不想做的事情。

至于本地 SE 服务——只是不要忘记偶尔从您忘记的孤立 selenium 驱动程序中清理操作系统 :)

原文由 Todor Minakov 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进