通过Cron执行Python POST请求脚本时出现ConnectionResetError问题求助
看起来你遇到了典型的终端环境与crontab环境差异导致的问题——脚本在终端能正常运行,但定时任务就触发连接重置错误。结合你提供的错误栈(SSL握手阶段失败),我整理了几个针对性的排查和解决方向:
1. 修复crontab的环境变量缺失问题
crontab的运行环境非常精简,默认的PATH和SSL相关环境变量(如CA证书路径)和终端完全不同,这很可能导致SSL握手失败,最终触发连接重置。
解决方法:
方法A:在crontab中指定完整环境变量
编辑你的crontab任务,开头添加Shell和PATH配置,确保和终端环境一致:# 编辑crontab crontab -e # 添加以下内容在任务上方 SHELL=/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin # 你的定时任务 * * * * * /usr/bin/python3.6 /location/sa/tb/uc/md/se/sea.py >> ~/Test_log.log 2>&1方法B:在脚本中强制指定SSL证书路径
如果是CA证书找不到导致的握手失败,可以在requests请求中直接指定系统CA证书的绝对路径:import requests # 替换为你系统的CA证书路径,常见路径如/etc/ssl/certs/ca-bundle.crt或/etc/ssl/certs/ca-certificates.crt CA_CERT_PATH = "/etc/ssl/certs/ca-bundle.crt" try: response = requests.post( "你的目标URL", data={"key": "value"}, verify=CA_CERT_PATH # 强制指定证书 ) response.raise_for_status() except Exception as e: print(f"请求失败: {str(e)}")
2. 检查crontab的网络访问限制
有些服务器会对crontab进程的网络访问做特殊限制,或者crontab的DNS解析配置和终端不同,导致无法正确连接目标服务器。
排查与解决:
在脚本开头添加DNS解析测试,确认目标域名能正确解析:
import socket try: ip = socket.gethostbyname("你的目标域名") print(f"解析到目标IP: {ip}") except socket.gaierror as e: print(f"DNS解析失败: {str(e)}")把这段日志输出到你的Test_log.log,看crontab执行时是否能正常解析域名。
如果是防火墙限制,可以联系运维确认crontab进程是否被允许访问目标端口(通常HTTPS是443)。
3. 添加网络请求重试机制
连接重置(Errno 104)也可能是临时的网络波动导致的——终端执行时刚好避开了波动,但定时任务触发时遇到了。添加重试逻辑可以应对这种情况:
import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry # 创建带重试机制的Session session = requests.Session() retry_strategy = Retry( total=3, # 总重试次数 backoff_factor=1, # 重试间隔(1秒、2秒、4秒...) status_forcelist=[429, 500, 502, 503, 504], # 需要重试的状态码 allowed_methods=["POST"] # 允许重试的请求方法 ) adapter = HTTPAdapter(max_retries=retry_strategy) session.mount("https://", adapter) session.mount("http://", adapter) try: response = session.post("你的目标URL", data={"key": "value"}) response.raise_for_status() print("请求成功") except requests.exceptions.RequestException as e: print(f"多次重试后仍失败: {str(e)}")
4. 确保脚本工作目录正确
crontab默认的工作目录是用户的home目录,而终端执行时工作目录是脚本所在目录。如果脚本中有依赖相对路径的资源(比如配置文件、本地证书),会导致加载失败间接影响网络请求。
在脚本开头添加切换工作目录的代码:
import os # 获取脚本所在的绝对路径 script_dir = os.path.dirname(os.path.abspath(__file__)) # 切换到脚本目录 os.chdir(script_dir)
内容的提问来源于stack exchange,提问作者Venkat

