简体   繁体   English

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

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

Background 背景

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. 我不想在每次更新后都必须手动进行干预,也不想禁用自动更新。

The root of the question 问题的根源

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文档中找不到任何相关选项。

Update: found root cause of post-upgrade slowness 更新:发现升级后缓慢的根本原因

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无法访问-尝试启动新会话时

The bad news 坏消息

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秒!

from chromium /src/chrome/test/chromedriver/chrome_launcher.cc@208: 来自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()); 

Until this code is changed to allow custom deadlines, the only option is a workaround. 在更改此代码以允许自定义截止日期之前,唯一的选择是解决方法。

The 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给出的答案帮助我走了正确的路,但是此解决方案在两个方面有所不同:

  1. The call to open standalone Chromium here is blocking, while webbrowser.open_new() is not. 此处打开独立Chromium的调用被阻止,而webbrowser.open_new()未被调用。
  2. Standalone Chromium is always launched before ChromeDriver whether it is needed or not. 无论是否需要,独立的Chromium总是在ChromeDriver之前启动。 I did this because waiting one minute for ChromeDriver to timeout, then waiting another 2.5 minutes for Chromium to start, then trying ChromeDriver again created a total delay of just over 3.5 minutes. 我这样做是因为等待一分钟让ChromeDriver超时,然后再等待2.5分钟让Chromium启动,然后再次尝试ChromeDriver造成的总延迟仅为3.5分钟。 Launching Chromium as the first action brings the total wait time down to about 2.5 minutes, as you skip the initial ChromeDriver timeout. 跳过最初的ChromeDriver超时操作, 首先启动Chromium可以使总等待时间减少到约2.5分钟。 On occasions when the long startup time doesn't occur, then this "double loading" of Chromium is negligible, as the whole process finishes in a matter of seconds. 在启动时间长的情况下,铬的这种“双重加载”可以忽略不计,因为整个过程只需几秒钟即可完成。

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.

相关问题 Twilio 收集我如何告诉收集在语音开始之前等待一段时间并开始收集 - Twilio gather how can I tell gather wait for sometime before speech starts and start collecting 如何找到适用于 chrome 版本 94.0.4606.61 的 chromedriver.exe - How can I find chromedriver.exe for chrome version 94.0.4606.61 如何使用 python 修复 heroku 中的 chrome 和 chromedriver 版本 - How can I fix the chrome and chromedriver version in heroku with python 如何判断 mongodb 服务器已启动? - How can I tell the mongodb server is up? 如何使用 Selenium2Library 在 Robot Framework 中向我的 chromedriver 添加扩展并远程启动 - How can I add an extension to my chromedriver at the Robot Framework with Selenium2Library and launch remotely 如何让 selenium chromedriver 等到它最大化 window? - How can I make the selenium chromedriver make wait until it maximizes the window? 如何告诉 beanstalkc 接收器在保留任务之前等待 X 秒? - How to tell a beanstalkc receiver to wait X seconds before reserving a task? 如何让我的python脚本等待,直到我告诉它在终端中继续执行? - How can I make my python script wait until I tell it it to continue in the terminal? 我如何使用存储在一个变量中的 chromedriver 打开许多链接 - how i can open up many links with chromedriver that are stored in one variable 我如何在 Java 中使用 selenium webdriver 启动 chrome,而不是作为访客,而是作为我的 chrome 配置文件? - how can i launch chrome using selenium webdriver in Java not as a guest but as my chrome profile?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM