如果通过 cron 执行,Firefox 的 Selenium 脚本会失败,但如果手动执行则可以正确运行

问题描述 投票:0回答:3

我配置了一个Python脚本(称为

test_fire7.py
),它使用Selenium和Firefox由
cron
在名为
e1
的Python虚拟环境中执行。如果从控制台手动执行,Python 脚本将正确运行。它在激活虚拟环境的情况下也能正确运行,无需显式激活环境,而是使用如下命令:
/root/pye/e1/bin/python3 /root/pye/test_fire7.py

这是

crontab
中的条目:

30 20 * * * cd /root/pye && /root/pye/e1/bin/python3 /root/pye/test_fire7.py command arg 2>&1 | logger -t mycmd

这是

test_fire7.py
的标题(我省略了脚本的其余部分,因为它本身运行正确):

from selenium import webdriver
from selenium.webdriver import FirefoxOptions
from selenium.webdriver.common.by import By

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

opts = FirefoxOptions()
opts.add_argument("--headless")

driver = webdriver.Firefox(options=opts)

这是 cron 运行脚本后的错误,在

syslog
中捕获:

root@wi-master:~/pye# grep 'mycmd' /var/log/syslog
May 27 20:30:01 wi-master mycmd: Traceback (most recent call last):
May 27 20:30:01 wi-master mycmd:   File "/root/pye/test_fire7.py", line 15, in <module>
May 27 20:30:01 wi-master mycmd:     driver = webdriver.Firefox(options=opts)
May 27 20:30:01 wi-master mycmd:   File "/root/pye/e1/lib/python3.8/site-packages/selenium/webdriver/firefox/webdriver.py", line 201, in __init__
May 27 20:30:01 wi-master mycmd:     super().__init__(command_executor=executor, options=options, keep_alive=True)
May 27 20:30:01 wi-master mycmd:   File "/root/pye/e1/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 286, in __init__
May 27 20:30:01 wi-master mycmd:     self.start_session(capabilities, browser_profile)
May 27 20:30:01 wi-master mycmd:   File "/root/pye/e1/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 378, in start_session
May 27 20:30:01 wi-master mycmd:     response = self.execute(Command.NEW_SESSION, parameters)
May 27 20:30:01 wi-master mycmd:   File "/root/pye/e1/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 440, in execute
May 27 20:30:01 wi-master mycmd:     self.error_handler.check_response(response)
May 27 20:30:01 wi-master mycmd:   File "/root/pye/e1/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 245, in check_response
May 27 20:30:01 wi-master mycmd:     raise exception_class(message, screen, stacktrace)
May 27 20:30:01 wi-master mycmd: selenium.common.exceptions.SessionNotCreatedException: Message: Expected browser binary location, but unable to find binary in default location, no 'moz:firefoxOptions.binary' capability provided, and no binary flag set on the command line

其他脚本可以使用 crontab 中完全相同类型的条目正确运行。所以我认为问题在某种程度上出在 Selenium 上。

我安装了 Firefox:

root@wi-master:~/pye# firefox -v
Mozilla Firefox 113.0.2

还有壁虎驱动程序:

root@wi-master:~/pye# geckodriver --version
geckodriver 0.33.0 ( 2023-05-22)

同样,如果手动执行,脚本会顺利通过。上面给出的 syslog 中的错误消息表明 Firefox 尚未安装。但事实并非如此!

更新: 我尝试在调用webdriver时添加geckodriver的可执行路径,但没有成功。我不确定我是否正确找到了可执行路径

root@wi-master:~# which geckodriver
/snap/bin/geckodriver

我也像这样显式地传递了Firefox二进制文件,但也没有成功。

from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
driver=webdriver.Firefox(firefox_binary=FirefoxBinary(getoutput("find /snap/firefox -name firefox").split("\n")[-1]), options=opts)

这样,Selenium 错误变为

selenium.common.exceptions.WebDriverException: Message: Service /snap/firefox/2667/usr/lib/firefox/firefox unexpectedly exited. Status code was: 255
python selenium-webdriver firefox cron geckodriver
3个回答
1
投票

看起来脚本的工作目录与手动启动时的工作目录不同。一种解决方案可能是从脚本中设置相对于脚本本身的工作目录。

假设您的脚本位于某个文件夹中,当您手动启动它时,您将从该文件夹启动它。如果将其添加到脚本中:

import os
import pathlib

os.chdir(pathlib.Path(__file__).parent)

这会将工作目录更改为脚本所在的文件夹。

当然,如果您从其他文件夹(例如您的主目录、配置文件目录等)手动启动脚本,您可以尝试更改为该文件夹。

但是,请记住,

cron
进程可能不允许访问您在交互式会话中有权访问的文件夹。如果您在执行之前设置了正确的工作目录,请确保允许该进程访问(并执行)那里的二进制文件。


0
投票

我终于找到了解决办法。在我在互联网上找到的所有建议都不适合我之后,经过多次尝试和错误才发生了这种情况。

为了完整起见,这是我的系统:

  • Ubuntu 20.04.6 LTS
  • Python 3.8.10
  • 硒4.9.1
  • Mozilla 火狐浏览器 113.0.2
  • geckodriver 0.33.0

我使用虚拟环境并从 root 运行脚本。

首先,我观察了 Firefox 和 geckodriver 所在的位置:

root@wikijs-master:~# which firefox
/snap/bin/firefox
root@wikijs-master:~# which geckodriver
/snap/bin/geckodriver

基于此,我将

export PATH=$PATH:/snap/bin/;
添加到上面的 crontab 条目中:

* * * * *  export PATH=$PATH:/snap/bin/; cd /root/pye && /root/pye/e1/bin/python3 /root/pye/test_fire7.py command arg 2>&1 | logger -t mycmd

这是 cron 可以执行的示例 Python 脚本!

from selenium import webdriver
from selenium.webdriver import FirefoxOptions

opts = FirefoxOptions()
opts.add_argument("--headless")

driver=webdriver.Firefox(options=opts)
driver.get("https://google.com")
print(driver.current_url)

我想指出的是,其他解决方案(例如在 webdriver 属性中添加可执行路径、绝对路径或二进制位置、更改工作目录或修改 cron 用户的权限)对我不起作用。


0
投票

这对我不起作用,因为 /snap/bin 已经在路径中(Ubuntu 22)。 尽管路径没问题,但我得到“/system.slice/cron.service is not a snap cgroup” 从 cron 运行任何快照。 我必须启动一个虚拟进程,只需加载硒模型并无限循环,然后它就起作用了......

更好的解决方案是添加: loginctl启用逗留用户

注销时似乎会发生一些 systemd 魔法

© www.soinside.com 2019 - 2024. All rights reserved.