[英]How can I tell ChromeDriver to wait longer for Chrome to launch before giving up?
I'm using Selenium and Python to automate display and navigation of a website in Chromium on Ubuntu MATE 16.04 on a Raspberry Pi 3. (Think unattended digital signage.) This combination was working great until today when the newest version of Chromium (with matching ChromeDriver) installed via automatic updates. 我正在使用Selenium和Python在Raspberry Pi 3上的Ubuntu MATE 16.04上的Chromium中自动显示和导航Chromium中的网站。(请考虑使用无人看管的数字标牌。)这种组合一直有效,直到今天最新版本的Chromium(具有匹配功能) ChromeDriver)通过自动更新安装。
Because Chromium needed to perform some upgrade housekeeping tasks the next time it started up, it took a little longer than usual. 由于Chromium在下一次启动时需要执行一些升级内务处理任务,因此它花费的时间比平常多一点。 Keep in mind that this is on a Raspberry Pi, so I/O is severely bottlenecked by the SD card.
请记住,它在Raspberry Pi上,因此I / O严重受到SD卡的瓶颈。 Unfortunately, it took long enough that my Python script failed because the ChromeDriver gave up on Chromium ever starting:
不幸的是,花了足够长的时间使我的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)
Of course, when the script dies after throwing this exception, the Chromium instance is killed before it can finish its housekeeping, which means that next time it has to start over, so it takes just as long as the last time and fails just as hard. 当然,当脚本在抛出此异常后死亡时,Chromium实例在完成其内务处理之前便被杀死,这意味着下次必须重新开始,因此它花费的时间与上次一样长,并且失败同样困难。
If I then manually intervene and run Chromium as a normal user, I just... wait... a minute... or two, for Chromium to finish its upgrade housekeeping, then it opens its browser window, and then I cleanly quit the application. 如果然后我手动干预并以普通用户身份运行Chromium,我只是……等一两分钟……让Chromium完成其升级内务处理,然后打开其浏览器窗口,然后我彻底退出应用程序。 Now that the housekeeping is done, Chromium starts up the next time at a more normal speed, so all of the sudden my Python script runs without any error because the ChromeDriver sees Chromium finish launching within its accepted timeout window.
现在,客房服务已经完成,Chromium下次将以更高的速度启动,因此我的Python脚本突然运行而没有任何错误,因为ChromeDriver看到Chromium在其可接受的超时窗口内完成了启动。
Everything will likely be fine until the next automatic update comes down, and then this same problem will happen all over again. 在下一次自动更新失败之前,一切都会很好,然后再次发生同样的问题。 I don't want to have to manually intervene after every update, nor do I want to disable automatic updates.
我不想在每次更新后都必须手动进行干预,也不想禁用自动更新。
How can I tell ChromeDriver not to give up so quickly on launching Chromium? 如何通知ChromeDriver在启动Chromium时不要这么快就放弃?
I looked for some sort of timeout value that I could set, but I couldn't find any in the ChromeDriver or Selenium for Python documentation. 我寻找了可以设置的某种超时值,但在ChromeDriver或Selenium for Python文档中找不到任何值。
Interestingly, there is a timeout
argument that can be passed to the Firefox WebDriver, as shown in the Selenium for Python API documentation : 有趣的是, 有一个
timeout
可以传递到火狐的webdriver,参数如图中硒的Python API文档 :
timeout – Time to wait for Firefox to launch when using the extension connection.
超时 –使用扩展连接时等待Firefox启动的时间。
This parameter is also listed for the Internet Explorer WebDriver, but it's notably absent in the Chrome WebDriver API documentation. 此参数也在Internet Explorer WebDriver中列出,但在Chrome WebDriver API文档中却不存在。
I also wouldn't mind passing something directly to ChromeDriver via service_args
, but I couldn't find any relevant options in the ChromeDriver docs. 我也不介意通过
service_args
将某些内容直接传递给ChromeDriver,但是我在ChromeDriver文档中找不到任何相关选项。
After struggling with finding a way to reproduce this problem in order to test solutions, I was able to pinpoint the reason Chromium takes forever to launch after an upgrade. 在努力寻找一种方法来重现此问题以测试解决方案后,我能够指出Chromium在升级后永久启动的原因。
It seems that, as part of its post-upgrade housekeeping, Chromium rebuilds the user's font cache. 看来,作为升级后内部整理的一部分,Chromium会重建用户的字体缓存。 This is a CPU & I/O intensive process that is especially hard on a Raspberry Pi and its SD card, hence the extreme 2.5 minute launch time whenever the font cache has to be rebuilt.
这是CPU和I / O密集型过程,在Raspberry Pi及其SD卡上特别困难,因此,每当需要重建字体缓存时,启动时间都将达到2.5分钟。
The problem can be reproduced by purposely deleting the font cache, which forces a rebuild: 可以通过有意删除字体缓存来重现该问题,这将强制进行重建:
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
You are right, there is no option to explicitly set the timeout
of the initial driver creation. 没错,没有选项可以明确设置初始驱动程序创建的
timeout
。 I would recommend visiting their git page HERE and creating a new issue. 我建议在这里访问他们的git页面并创建一个新问题。 It also has the links for the direct ChromeDriver site in case you want to create a bug there.
如果您要在其中创建错误,它也具有指向直接ChromeDriver网站的链接。 Currently, there is no option to set timeout that I could find.
目前,没有可以设置超时的选项。
You could try something like this in the meantime though: 您可以同时尝试类似的方法:
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
Here is the documentation on webbrowser: https://docs.python.org/3/library/webbrowser.html 这是关于webbrowser的文档: https : //docs.python.org/3/library/webbrowser.html
As per your question without your code trial it would be tough to analyze the reason behind the error which you are seeing as : 根据您的问题,无需进行代码试用,就很难分析您所看到的错误背后的原因:
selenium.common.exceptions.WebDriverException: Message: chrome not reachable
Perhaps a more details about the version info of the binaries you are using would have helped us in someway. 也许有关正在使用的二进制文件的版本信息的更多详细信息会在某种程度上对我们有所帮助。
Factually, asking ChromeDriver to wait longer for Chrome to launch before giving up won't help us as the default configuration of ChromeDriver takes care of the optimum needs. 实际上 ,要求ChromeDriver等待更长的时间才能放弃启动Chrome ,这对我们无济于事,因为ChromeDriver的默认配置可以满足最佳需求。
However WebDriverException: Message: chrome not reachable is pretty common issue when the binary versions are incompatible. 但是,当二进制版本不兼容时, WebDriverException:消息:无法访问chrome是很常见的问题。 You can find a detailed discussion about this issue at org.openqa.selenium.WebDriverException: chrome not reachable - when attempting to start a new session
您可以在org.openqa.selenium.WebDriverException中找到有关此问题的详细讨论:chrome无法访问-尝试启动新会话时
It turns out that not only is there no timeout
option for Selenium to pass to ChromeDriver, but short of recompiling your own custom ChromeDriver, there is currently no way to change this value programmatically whatsoever. 事实证明,不仅Selenium没有
timeout
选项可以传递给ChromeDriver,而且缺少重新编译自己的自定义ChromeDriver的能力,目前还无法以编程方式更改此值。 Sadly, looking at the source code shows that Google has hard-coded a timeout value of 60 seconds! 可悲的是, 查看源代码表明Google已将超时值硬编码为60秒!
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());
Until this code is changed to allow custom deadlines, the only option is a workaround. 在更改此代码以允许自定义截止日期之前,唯一的选择是解决方法。
I ended up taking an approach that "primed" Chromium before having Selenium call ChromeDriver. 我最终采取了一种在硒调用ChromeDriver之前“灌注”铬的方法。 This gets that one-time, post-upgrade slow start out of the way before ChromeDriver ever begins its countdown.
这样一来,升级前的缓慢启动就不会影响ChromeDriver开始倒计时了。 The answer @PixelEinstein gave helped lead me down the right path, but this solution differs in two ways:
@PixelEinstein给出的答案帮助我走了正确的路,但是此解决方案在两个方面有所不同:
webbrowser.open_new()
is not. webbrowser.open_new()
未被调用。 Here's the code snippet: 这是代码片段:
#!/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...
Before instantiating a webdriver.Chrome()
object, this waits for Chromium to finish its post-upgrade housekeeping no matter how long it takes. 在实例化
webdriver.Chrome()
对象之前,这将等待Chromium完成升级后的内务处理,无论花费多长时间。 Chromium is launched in headless mode where --dump-dom
is a one-shot operation that writes the requested web page (in this case about:blank
) to stdout, which is ignored. Chromium以无头模式启动,其中
--dump-dom
是一次操作,将请求的网页(在本例中为about:blank
)写入stdout,该操作将被忽略。 Chromium self-terminates after completing the operation, which then returns from the subprocess.run()
call, unblocking program flow. 完成该操作后,铬会自行终止,然后从
subprocess.run()
调用返回,从而解除程序流。 After that, it's safe to let ChromeDriver start its countdown, as Chromium will launch in a matter of seconds. 之后,放心让ChromeDriver开始倒计时是安全的,因为Chromium将在几秒钟内启动。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.