我遇到了一个奇怪的问题,过去两周我一直在绞尽脑汁解决这个问题,到处搜索,还喝酒来洗去失败的痛苦。
问题是,当我从 cron 运行我的警报脚本时,什么都没有重定向到我的日志文件,并且脚本似乎不起作用。但是,当我注释掉 selenium 中一个看似毫无意义的选项时,日志记录就可以正常工作。在 cron 之外运行时,脚本可以完美运行。顺便说一下,我使用的是非 sudo cron,因为我的 python 环境就是在那里设置的。
该脚本基本上会获取一些信息,并将其输入到一个非常好的 TTS 引擎(自然阅读器)中,然后在早上播放。我不想为 TTS 或自然阅读器付费,这就是我使用 selenium 的原因
代码
这是我的 cron 脚本,我省略了其他 cron 条目,因为它们不重要:
@reboot sh scripts/YakScripts.sh -alarm > scripts/logs/alarm.log 2>&1
这是我的 YakScripts.sh 文件,同样,我省略了它的主要内容:
#!/usr/bin/env bash
TZ=":America/New_York" date
export PYTHONPATH=${PYTHONPATH}:"scripts"
case "$1" in
-alarm) python3 scripts/Alarm/alarm.py ;;
*) echo "Thats not a function, dumbass."
;;
esac
这是我的闹钟脚本:
import Alarm.Weather.getDailyForecast as weather
import Alarm.SunCycles.suncycles as suncycles
import TTS.speak as voice
from datetime import date
today = date.today()
# dd/mm/YY
naturalDate = today.strftime("%B %d, %Y")
print(naturalDate)
dayOfWeek = today.strftime("%A")
print(dayOfWeek)
alarmText = "Good Morning. \n"
alarmText += "Today is " + dayOfWeek + ". " + naturalDate + ".\n"
alarmText += weather.getMostRecentForecast() + "\n\n"
alarmText += "Today, the sun rises at " + suncycles.getSunrise() + ".\n"
alarmText += "and sets at " + suncycles.getSunset() + ".\n"
print(alarmText)
voice.speak(alarmText)
最后(也是最重要的一点)这是我的演讲脚本,我删除了大部分内容,因为我认为 naturalReader 不会喜欢我发布这些内容。但我测试过,它的功能是一样的:
import time
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
import TTS.locators as locators
import globalData
selectedVoice = globalData.tts["voice"]
max_stale_tries = globalData.tts["max_retries"]
def speak(message):
options = Options()
#options.add_argument("--headless")
driver = webdriver.Firefox(options=options)
driver.get("https://www.naturalreaders.com/online/")
print("Loaded the web page")
time.sleep(3)
问题
因此,问题就在这里,当我不注释掉其中的 headless 行(speak.py 的第 15 行)时,我的 alarm.log 文件如下所示:
Tue Feb 9 21:08:03 EST 2021
当我注释掉该行时,它看起来是这样的:
Tue Feb 9 21:27:43 EST 2021
February 10, 2021
Wednesday
Good Morning.
Today is Wednesday. February 10, 2021.
Tonight the forecast is Snow showers before 10pm, then snow showers and patchy freezing drizzle. Cloudy, with a low around 8. Wind chill values as low as -6. Northeast wind 8 to 12 mph.
Wednesday the forecast is Snow showers before 7am. Cloudy, with a high near 16. Wind chill values as low as -7. Northeast wind 10 to 14 mph, with gusts as high as 18 mph.
Today, the sun rises at 07:29 AM.
and sets at 06:12 PM.
Traceback (most recent call last):
File "../../../../../../../../scripts/Alarm/alarm.py", line 35, in <module>
voice.speak(alarmText)
File "/scripts/TTS/speak.py", line 16, in speak
driver = webdriver.Firefox(options=options)
File "/home/appa/.local/lib/python3.8/site-packages/selenium/webdriver/firefox/webdriver.py", line 170, in __init__
RemoteWebDriver.__init__(
File "/home/appa/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 157, in __init__
self.start_session(capabilities, browser_profile)
File "/home/appa/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 252, in start_session
response = self.execute(Command.NEW_SESSION, parameters)
File "/home/appa/.local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "/home/appa/.local/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: Process unexpectedly closed with status 1
我知道此错误与 webdriver 无法连接到显示器有关,这就是为什么我需要无头运行它。
还有一件事,我可以在 htop 中看到 geckodriver/python3 进程,但是同样,没有从 alarm.py 脚本中得到任何输出。
我真的只是想知道为什么当该行取消注释时我会得到输出,而在正常运行(无头)时却不会得到输出。
答案1
通过cron
、运行的作业crontab
不会在桌面上的同一运行时环境中运行。您的任何PATH
更改或其他环境变量设置都不会自动传播到您的cron
作业。例如,没有$DISPLAY
,因此 GUI 程序需要特殊处理(阅读man xhost
)。
cron
人们可以在crontab
文件 Read中为所有作业设置环境变量man 5 crontab
。
echo "=== set ===";set;echo "=== env ===";env | sort;echo "=== alias ===";alias
查看每个环境中的结果 。
由于command
该行的一部分crontab
默认由 解释/bin/sh
,其语法比 更简单/bin/bash
,因此我建议command
调用一个bash
脚本(可执行、已安装、以 开头#!/bin/bash
)来设置环境,然后调用所需的程序。