使用cron启动Selenium和Chromedriver失败

10

在CentOS7上,使用Selenium和Chromedriver编写的Python脚本在无界面模式下手动调用时可以正常运行。

options = webdriver.ChromeOptions()
options.add_argument('headless')
options.add_argument('no-sandbox')
self.driver = webdriver.Chrome(chrome_options=options)

当使用crontab启动脚本时,它会在第4行(如上所示)抛出此异常。完整的回溯信息请见底部。

selenium.common.exceptions.WebDriverException: Message: unknown error: Chrome failed to start: exited abnormally (Driver info: chromedriver=2.38.552522

Cron是使用crontab -e设置的

* * * * * cd /to/path && /to/path/.virtualenvs/selenium/bin/python /to/path/script.py -t arg1 arg2 > /to/path/log.txt 2>&1

这导致出现了像 chromedriver 找不到的错误。然后我添加了以下内容到 crontab -e 中。
1) 使用 bash 而不是 sh,虽然在 sh 中手动启动 python 脚本可以正常工作
2) 指定 chromedriver 的路径。
SHELL=/bin/bash
PATH=/usr/local/bin/

我尝试了一些网络上的建议,例如在我的脚本中添加--no-sandbox选项以解决问题。但是这些方法都没有起到帮助作用。请注意,我正在使用chrome无头模式,因此我认为在cron中不需要导出DISPLAY=:0或Xvfb库等内容。
Python 3.6.1 Selenium 3.4.3 Chromedriver 2.38.552522 google-chrome-stable 65.0.3325.181
完整的回溯信息
Exception in thread <name>:
Traceback (most recent call last):
  File "/usr/lib64/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()
  File "/usr/lib64/python3.6/threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "/path/to/script.py", line 53, in start
    self.site_scrape(test_run)
  File "/path/to/script.py", line 65, in site
    self.driver = webdriver.Chrome(chrome_options=options)
  File "/home/<user>/.virtualenvs/selenium/lib64/python3.6/site-packages/selenium/webdriver/chrome/webdriver.py", line 69, in __init__
    desired_capabilities=desired_capabilities)
  File "/home/<user>/.virtualenvs/selenium/lib64/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 98, in __init__
    self.start_session(desired_capabilities, browser_profile)
  File "/home/<user>/.virtualenvs/selenium/lib64/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 188, in start_session
    response = self.execute(Command.NEW_SESSION, parameters)
  File "/home/<user>/.virtualenvs/selenium/lib64/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 256, in execute
    self.error_handler.check_response(response)
  File "/home/<user>/.virtualenvs/selenium/lib64/python3.6/site-packages/selenium/webdriver/remote/errorhandler.py", line 194, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.38.552522 (437e6fbedfa8762dec75e2c5b3ddb86763dc9dcb),platform=Linux 4.14.12-x86_64-linode92 x86_64)

你能否尝试通过 crontab -u 指定用户,并确保你的 chromedriver 可执行文件权限正确吗? - ekostadinov
crontab -u <user> -l shows the correct cron entry. chromedriver has following permissions -rwxr-xr-x 1 root root 7872560 Mar 2 02:19 chromedriver - Jim B
是的,看起来没问题。我最后的建议是尝试使用2.372.38版本的chromedriver,因为两者都支持您的浏览器版本。 - ekostadinov
谢谢。但是仍然存在相同的错误selenium.common.exceptions.WebDriverException: Message: unknown error: Chrome failed to start: exited abnormally (Driver info: chromedriver=2.38.552522) - Jim B
请在问题中更新错误堆栈跟踪。 - undetected Selenium
5个回答

15

终于找到解决方案了。这个问题已经困扰我很久了。问题是在cron中缺少以下路径:/usr/bin和/usr/sbin。现在完整的cron看起来像这样:

SHELL=/bin/bash
PATH=/usr/local/bin/:/usr/bin:/usr/sbin
* * * * * cd /to/path && /to/path/.virtualenvs/selenium/bin/python /to/path/script.py -t arg1 arg2 > /to/path/log.txt 2>&1

应注意,由于此操作会覆盖PATH变量,可能会在其他地方引起混乱。 - misantroop
3
非常感谢。我也遇到了同样的问题……我在终端上运行了 echo $PATH 命令,然后将结果放入 crontab 中的 PATH 中,问题得到了解决。 - Hooman Bahreini
1
只是想补充一下,这个方法(显然我猜,因为问题与Python或Chromedriver无关)也适用于Ruby和Geckodriver。我发现了这个答案,所以其他人可能也会发现,但也许值得更新标签? - defuzed

5
以下步骤对我有帮助:
  1. 在我的crontab中添加'DISPLAY=:1'
  2. 在crontab中设置正确的shell(我使用'zsh')
  3. 源环境变量,因为crontab默认不执行此操作
  4. 使用chromedriver的绝对路径

TLDR

  1. The required modifications to your crontab would be:

    SHELL=/bin/zsh
    05 * * * * export DISPLAY=:<displayNumber> && source /home/<username>/.zshrc && cd <absoluteExecutableDirectory> && ./<pythonFile> >> log.log 2>&1
    
  2. Use the following line to initialize the selenium chrome driver:

    driver = webdriver.Chrome(<absoluteDriverPath>,...)
    

请用相应的值替换尖括号内的所有内容。

1. 设置显示

要确定要添加到您的crontab中的显示,请使用:

    env | grep 'DISPLAY'

接着将这段代码添加到你的crontab命令中:

    export DISPLAY=:1

2. 设置shell

  • If you have a non-default shell*, then set the shell. Find out the location of your shell with one of the two commands

    which bash
    which zsh
    

    Then set the shell to the response of the previous command (in your crontab):

    SHELL=/bin/zsh
    

3. 资源环境变量

根据您使用的是bash还是zsh,请添加以下代码片段中的一个到您的crontab命令中:

    source /home/<username>/.zshrc
    source /home/<username>/.bashrc

4. 使用绝对路径指定你的chromedriver:

当初始化驱动程序时,请使用以下行,其中 <path_to_chromedriver> 指向Selenium Chrome驱动程序。

    driver = webdriver.Chrome(<absoluteDriverPath>,options=options)

其他

    >> log.log 2>&1

该选项表示所有输出都将被写入文件中,这有助于更容易地调试crontabs。


你在这里指向哪个可执行文件:&& cd <absoluteExecutableDirectory> &&?谢谢。 - will-hedges
非常感谢您,DISPLAY变量拯救了我的一天。 - DiveIntoML

1

我不知道是否晚了,但我认为我的解决方案将帮助很多人。经过1个半小时的尝试,我找到了解决方案。以下是解决步骤:

  1. 打开终端并运行以下命令:

echo $DISPLAY

让这个命令的输出是::0

  1. 打开crontab进行编辑:

crontab -e

  1. 在crontab中添加以下行:
     DISPLAY=:0 
     ## If output of "echo $DISPLAY" is: ":1", then change the above line to: "DISPLAY=:1" (without quotes)


     ## if running the python file every 2 minutes:

     # If firefox is used for selenium automation:

     */2 * * * * export PATH=$PATH:path_to_python_executable_folder:geckodriver_folder_path_for_firefox; python path_to_your_python_script.py

     # If chrome is used for selenium automation:

     */2 * * * * export PATH=$PATH:path_to_python_executable_folder:chromedriver_folder_path; python path_to_your_python_script.py

1
在Ubuntu 18.04上,Python版本为3.6.9:
这是我的主要工作站,所以我始终有一个已登录的X会话。
我的Selenium调用:
#!/usr/bin/python3
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
driver = webdriver.Firefox()
location = 'http://example.com'
driver.get(location)

我放在crontab里的内容:

33 14 * * * DISPLAY=:0 lxterminal --working-directory=/home/user/Documents/ -e /home/user/bin/get.stats.by.zip.py > /home/user/gbzp.log 2>&1

lxterminal是一个相对简单的终端程序,我倾向于在大多数终端操作中使用它,而不是使用apt-get安装的gnome-terminal。


0
希望这能帮到某人。 我尝试了很多选项,但没有什么能帮到我。 我的目标是在Linux服务器上启动无头Chrome,并使用Chrome的功能下载文件,因为该网站不会给我文件的链接。 我需要定期启动脚本,所以我选择使用cron作业。
使用--headles=old选项,我可以启动Chrome,但无法从cron和命令行窗口下载文件, 使用--headless=new选项,我可以从命令行窗口下载文件,但无法从cron作业中下载。
Ubuntu 18.04.2 LTS,使用Python 2.7。
目前我的设置如下:
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
prefs = {"download.default_directory": "path to your directory"}
options.add_experimental_option("prefs", prefs)

driver = webdriver.Chrome('/usr/lib/chromium-browser/chromedriver', options=options)

也许这一行也可以起作用:driver = webdriver.Chrome(options=options) 通常在Linux中,你应该始终关注谁启动了脚本和谁拥有文件。 所以我将cron作业从www-data更改为root用户,然后获得了我的结果。
wrong: 0 10 * * * www-data {your scritp} 2>&1
write: 0 10 * * * root {your scritp} 2>&1

对于那些这并没有帮助的人,我祝你们好运,希望你们能找到解决办法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接