我使用Selenium和Python在Raspberry Pi 3上的Ubuntu MATE 16.04上自动显示和导航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
参数,可以传递给Firefox WebDriver,as shown in the Selenium for Python API documentation:
超时 - 使用扩展程序连接时等待Firefox启动的时间。
此参数也列在Internet Explorer WebDriver中,但在Chrome WebDriver API文档中显然不存在。
我也不介意通过service_args
将某些内容直接传递给ChromeDriver,但我无法在ChromeDriver文档中找到任何相关选项。
在努力寻找重现此问题的方法以便测试解决方案之后,我能够确定Chromium在升级后永远启动的原因。
似乎作为升级后管家的一部分,Chromium重建了用户的字体缓存。这是一个CPU&amp;对于Raspberry Pi及其SD卡来说,I / O密集型进程尤其困难,因此每当必须重建字体缓存时,启动时间最长为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
答案 0 :(得分:0)
您是对的,没有选项可以显式设置初始驱动程序创建的timeout
。我建议访问他们的git页面HERE并创建一个新问题。它还具有直接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
答案 1 :(得分:0)
根据您的问题,如果没有您的代码试用,很难分析您所看到的错误背后的原因:
selenium.common.exceptions.WebDriverException: Message: chrome not reachable
或许有关您正在使用的二进制文件的版本信息的详细信息可能会对我们有所帮助。
事实上,要求 ChromeDriver 等待更长时间才能启动 Chrome ,然后放弃它将无法帮助我们,因为 ChromeDriver 的默认配置需要关心最佳需求。
然而 WebDriverException:消息:chrome无法访问是二进制版本不兼容时非常常见的问题。您可以在org.openqa.selenium.WebDriverException: chrome not reachable - when attempting to start a new session
找到有关此问题的详细讨论答案 2 :(得分:0)
事实证明,Selenium不仅没有传递给ChromeDriver的timeout
选项,而且还没有重新编译自己的自定义ChromeDriver,目前无法以编程方式更改此值。遗憾的是,looking at the source code显示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());
在更改此代码以允许自定义截止日期之前,唯一的选择是解决方法。
在Selenium召唤ChromeDriver之前,我最终选择了一种“引导”Chromium的方法。这使得ChromeDriver开始倒计时之前的一次性升级后缓慢启动。 @PixelEinstein给出的答案帮助我走上了正确的道路,但这个解决方案在两个方面有所不同:
webbrowser.open_new()
则不是。以下是代码段:
#!/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,这将被忽略。 Chromium在完成操作后自行终止,然后从subprocess.run()
调用,解锁程序流返回。之后,让ChromeDriver开始倒计时是安全的,因为Chromium将在几秒钟内启动。