提问者:小点点

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


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


共3个答案

匿名用户

否,退出脚本后无法重新连接到上一个Web浏览会话。 即使您能够从以前的浏览上下文中提取会话IDcookies和其他会话属性,您仍然无法将这些属性作为钩子传递给WebDriver。

更干净的方法是调用webdriver.quit(),然后跨转一个新的浏览上下文。

已经有很多讨论和尝试将WebDriver重新连接到现有的正在运行的浏览上下文。 在讨论允许webdriver附加到运行中的浏览器时,Simon Stewart[webdriver的创造者]明确提到:

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

WebDriver.Firefox.UseExisting未实现

匿名用户

硒<->; 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库会自动为它启动一个新的会话--现在您有一个带有两个会话(浏览器实例)的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)--通常工作正常。

问题是,对于远程会话,第二部分是缺失的--本地机器无法控制远程进程,这是远程集线器的工作。 因此,第2部分实际上是一个passpython语句-一个no-op。

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

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

匿名用户

如果不深入了解为什么您认为保持打开的浏览器窗口将解决速度慢的问题,那么您实际上并不需要一个句柄来做到这一点。 只需继续运行测试,而不关闭会话,换句话说,不调用driver.quit(),就像您自己提到的那样。 这里的问题是,框架有自己的运行程序吗? 比如cucumber?

在任何情况下,您都必须有一些“设置”和“清理”代码。 所以您需要做的是在“清理”阶段确保浏览器恢复到初始状态。 这意味着:

  • 显示空白页
  • 会话的cookies
  • 将被擦除