繁体   English   中英

如何通知ChromeDriver放弃等待Chrome启动的时间更长?

[英]How can I tell ChromeDriver to wait longer for Chrome to launch before giving up?

背景

我正在使用Selenium和Python在Raspberry Pi 3上的Ubuntu MATE 16.04上的Chromium中自动显示和导航Chromium中的网站。(请考虑使用无人看管的数字标牌。)这种组合一直有效,直到今天最新版本的Chromium(具有匹配功能) ChromeDriver)通过自动更新安装。

由于Chromium在下一次启动时需要执行一些升级内务处理任务,因此它花费的时间比平常多一点。 请记住,它在Raspberry Pi上,因此I / O严重受到SD卡的瓶颈。 不幸的是,花了足够长的时间使我的Python脚本失败,因为ChromeDriver从一开始就放弃了Chromium:

Traceback (most recent call last):
  File "call-tracker-start", line 15, in <module>
    browser = webdriver.Chrome(executable_path=chromedriver_path, options=chrome_options)
  File "/home/pi/.local/lib/python3.5/site-packages/selenium/webdriver/chrome/webdriver.py", line 75, in __init__
    desired_capabilities=desired_capabilities)
  File "/home/pi/.local/lib/python3.5/site-packages/selenium/webdriver/remote/webdriver.py", line 154, in __init__
    self.start_session(desired_capabilities, browser_profile)
  File "/home/pi/.local/lib/python3.5/site-packages/selenium/webdriver/remote/webdriver.py", line 243, in start_session
    response = self.execute(Command.NEW_SESSION, parameters)
  File "/home/pi/.local/lib/python3.5/site-packages/selenium/webdriver/remote/webdriver.py", line 312, in execute
    self.error_handler.check_response(response)
  File "/home/pi/.local/lib/python3.5/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: chrome not reachable
  (Driver info: chromedriver=2.35 (0),platform=Linux 4.4.38-v7+ armv7l)

当然,当脚本在抛出此异常后死亡时,Chromium实例在完成其内务处理之前便被杀死,这意味着下次必须重新开始,因此它花费的时间与上次一样长,并且失败同样困难。

如果然后我手动干预并以普通用户身份运行Chromium,我只是……等一两分钟……让Chromium完成其升级内务处理,然后打开其浏览器窗口,然后我彻底退出应用程序。 现在,客房服务已经完成,Chromium下次将以更高的速度启动,因此我的Python脚本突然运行而没有任何错误,因为ChromeDriver看到Chromium在其可接受的超时窗口内完成了启动。

在下一次自动更新失败之前,一切都会很好,然后再次发生同样的问题。 我不想在每次更新后都必须手动进行干预,也不想禁用自动更新。

问题的根源

如何通知ChromeDriver在启动Chromium时不要这么快就放弃?

我寻找了可以设置的某种超时值,但在ChromeDriver或Selenium for Python文档中找不到任何值。

有趣的是, 一个timeout可以传递到火狐的webdriver,参数如图中硒的Python API文档

超时 –使用扩展连接时等待Firefox启动的时间。

此参数也在Internet Explorer WebDriver中列出,但在Chrome WebDriver API文档中却不存在。

我也不介意通过service_args将某些内容直接传递给ChromeDriver,但是我在ChromeDriver文档中找不到任何相关选项。

更新:发现升级后缓慢的根本原因

在努力寻找一种方法来重现此问题以测试解决方案后,我能够指出Chromium在升级后永久启动的原因。

看来,作为升级后内部整理的一部分,Chromium会重建用户的字体缓存。 这是CPU和I / O密集型过程,在Raspberry Pi及其SD卡上特别困难,因此,每当需要重建字体缓存时,启动时间都将达到2.5分钟。

可以通过有意删除字体缓存来重现该问题,这将强制进行重建:

pi@rpi-dev1:~$ killall chromium-browser
pi@rpi-dev1:~$ time chromium-browser --headless --disable-gpu --dump-dom 'about:blank'
[0405/132706.970822:ERROR:gpu_process_transport_factory.cc(1019)] Lost UI shared context.
<html><head></head><body></body></html>

real    0m0.708s
user    0m0.340s
sys     0m0.200s

pi@rpi-dev1:~$ rm -Rf ~/.cache/fontconfig
pi@rpi-dev1:~$ time chromium-browser --headless --disable-gpu --dump-dom 'about:blank'
[0405/132720.917590:ERROR:gpu_process_transport_factory.cc(1019)] Lost UI shared context.
<html><head></head><body></body></html>

real    2m9.449s
user    2m8.670s
sys     0m0.590s

没错,没有选项可以明确设置初始驱动程序创建的timeout 我建议在这里访问他们的git页面并创建一个新问题。 如果您要在其中创建错误,它也具有指向直接ChromeDriver网站的链接。 目前,没有可以设置超时的选项。

您可以同时尝试类似的方法:

import webbrowser
from selenium import webdriver
from selenium.common.exceptions import WebDriverException

try:
    driver = webdriver.Chrome()
except WebDriverException:
    webbrowser.open_new('http://www.Google.com')
# Let this try and get Chrome open, then go back and use webdriver

这是关于webbrowser的文档: https : //docs.python.org/3/library/webbrowser.html

根据您的问题,无需进行代码试用,就很难分析您所看到的错误背后的原因:

selenium.common.exceptions.WebDriverException: Message: chrome not reachable

也许有关正在使用的二进制文件的版本信息的更多详细信息会在某种程度上对我们有所帮助。

实际上 ,要求ChromeDriver等待更长的时间才能放弃启动Chrome ,这对我们无济于事,因为ChromeDriver的默认配置可以满足最佳需求。

但是,当二进制版本不兼容时, WebDriverException:消息:无法访问chrome是很常见的问题。 您可以在org.openqa.selenium.WebDriverException中找到有关此问题的详细讨论:chrome无法访问-尝试启动新会话时

坏消息

事实证明,不仅Selenium没有timeout选项可以传递给ChromeDriver,而且缺少重新编译自己的自定义ChromeDriver的能力,目前还无法以编程方式更改此值。 可悲的是, 查看源代码表明Google已将超时值硬编码为60秒!

来自chrome /src/chrome/test/chromedriver/chrome_launcher.cc@208:
 std::unique_ptr<DevToolsHttpClient> client(new DevToolsHttpClient( address, context_getter, socket_factory, std::move(device_metrics), std::move(window_types), capabilities->page_load_strategy)); base::TimeTicks deadline = base::TimeTicks::Now() + base::TimeDelta::FromSeconds(60); Status status = client->Init(deadline - base::TimeTicks::Now()); 

在更改此代码以允许自定义截止日期之前,唯一的选择是解决方法。

解决方法

我最终采取了一种在硒调用ChromeDriver之前“灌注”铬的方法。 这样一来,升级前的缓慢启动就不会影响ChromeDriver开始倒计时了。 @PixelEinstein给出的答案帮助我走了正确的路,但是此解决方案在两个方面有所不同:

  1. 此处打开独立Chromium的调用被阻止,而webbrowser.open_new()未被调用。
  2. 无论是否需要,独立的Chromium总是在ChromeDriver之前启动。 我这样做是因为等待一分钟让ChromeDriver超时,然后再等待2.5分钟让Chromium启动,然后再次尝试ChromeDriver造成的总延迟仅为3.5分钟。 跳过最初的ChromeDriver超时操作, 首先启动Chromium可以使总等待时间减少到约2.5分钟。 在启动时间长的情况下,铬的这种“双重加载”可以忽略不计,因为整个过程只需几秒钟即可完成。

这是代码片段:

 #!/usr/bin/env python3 import subprocess from selenium import webdriver some_site = 'http://www.google.com' chromedriver_path = '/usr/lib/chromium-browser/chromedriver' # Block until Chromium finishes launching and self-terminates subprocess.run(['chromium-browser', '--headless', '--disable-gpu', '--dump-dom', 'about:blank']) browser = webdriver.Chrome(executable_path=chromedriver_path) browser.get(some_site) # Continue on with your Selenium business... 

在实例化webdriver.Chrome()对象之前,这将等待Chromium完成升级后的内务处理,无论花费多长时间。 Chromium以无头模式启动,其中--dump-dom是一次操作,将请求的网页(在本例中为about:blank )写入stdout,该操作将被忽略。 完成该操作后,铬会自行终止,然后从subprocess.run()调用返回,从而解除程序流。 之后,放心让ChromeDriver开始倒计时是安全的,因为Chromium将在几秒钟内启动。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM