You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

crontab调度的Selenium脚本偶发Chromedriver启动失败问题排查

问题描述

通过crontab调度搭载Chromedriver的Selenium脚本自动运行,脚本会生成多个进程,每个进程独立启动Chromedriver实例。但存在约50%概率所有进程的Chromedriver均启动失败,手动启动脚本则完全正常。

相关信息

代码结构

main.py

import multiprocessing as mp

if __name__ == '__main__':
    pool = mp.Pool()
    result = pool.starmap_async(book_job, parameter_list)
    pool.close()
    pool.join()

book.py

import func_timeout # type: ignore
from func_timeout import func_set_timeout
import traceback
import logging
from selenium import webdriver
from selenium.webdriver.chrome.service import Service

def book_job():
    #......
    try:
        book_result = book()
        return message + book_result
    except Exception:
        traceback.print_exc()
        return message + 'book failed'
    #......

def book():
    #......
    try:
        driver = wait_book_page()
    except func_timeout.exceptions.FunctionTimedOut:
        logging.error("wait book page timeout")
        driver.quit()
        return "Time out to wait book page enabled"
    #......
    
 
@func_set_timeout(120)
def wait_book_page():

    options = webdriver.ChromeOptions()

    options.add_argument('--headless')
    options.add_argument('--disable-gpu')
    options.add_argument('--no-sandbox')

    try:
        webdriver_service = Service('/usr/bin/chromedriver')
        driver = webdriver.Chrome(service=webdriver_service,options=options)
        logging.info('chromedriver started')
    except Exception:
        traceback.print_exc()
        raise Exception('chromedriver started failed')
    #......

错误信息

Traceback (most recent call last):
File "/home/***/book.py", line 93, in wait_book_page
driver = webdriver.Chrome(service=webdriver_service,options=options)
File "/home/***/miniconda3/lib/python3.9/site-packages/selenium/webdriver/chrome/webdriver.py", line 81, in __init__
super().__init__(
File "/home/***/miniconda3/lib/python3.9/site-packages/selenium/webdriver/chromium/webdriver.py", line 103, in __init__
self.service.start()
File "/home/***/miniconda3/lib/python3.9/site-packages/selenium/webdriver/common/service.py", line 106, in start
self.assert_process_still_running()
File "/home/***/miniconda3/lib/python3.9/site-packages/selenium/webdriver/common/service.py", line 119, in assert_process_still_running
raise WebDriverException(f"Service {self.path} unexpectedly exited. Status code was: {return_code}")
selenium.common.exceptions.WebDriverException: Message: Service /usr/bin/chromedriver unexpectedly exited. Status code was: 1

Traceback (most recent call last):
File "/home/***/main.py", line 145, in book_job
book_result = book(session, venue_list, time, space_num)
File "/home/***/book.py", line 25, in book
driver = wait_book_page(session, base_url+venue_list[0])
File "/home/***/miniconda3/lib/python3.9/site-packages/func_timeout/dafunc.py", line 185, in <lambda>
return wraps(func)(lambda args, kwargs : func_timeout(defaultTimeout, func, args=args, kwargs=kwargs))
File "/home/***/miniconda3/lib/python3.9/site-packages/func_timeout/dafunc.py", line 108, in func_timeout
raise_exception(exception)
File "/home/***/miniconda3/lib/python3.9/site-packages/func_timeout/py3_raise.py", line 7, in raise_exception
raise exception[0] from None
File "/home/***/book.py", line 103, in wait_book_page
raise Exception('chromedriver started failed')

crontab配置

59 8 * * * username DISPLAY=:0 /home/***/miniconda3/bin/python /home/***/main.py >> /home/***/out.log 2>&1

环境信息

  • ubuntu22.04.1 LTS
  • Linux 5.15.0-52-generic
  • ChromeDriver 111.0.5563.146 (2b5ec366bb5b68dacca9719d5d83cb7e61fb6431-refs/branch-- heads/5563@{#1238})
  • conda 23.1.0
  • python 3.9.12

已尝试重装chromium和chromedriver、在另一台机器部署环境,问题依旧;手动执行与cron相同账号和命令无问题。


排查思路与建议

1. 环境变量差异问题

crontab的执行环境变量远少于用户手动登录的环境,即使指定了DISPLAY=:0,仍可能缺少关键变量:

  • 在crontab命令前追加完整的环境变量导入,比如先执行source /home/***/.bashrc(如果是bash)或source /home/***/.profile,确保conda环境和Chrome相关的路径、变量都能被正确加载:
    59 8 * * * username source /home/***/.bashrc && DISPLAY=:0 /home/***/miniconda3/bin/python /home/***/main.py >> /home/***/out.log 2>&1
    
  • 或者在脚本开头显式设置环境变量,比如添加PATH、LD_LIBRARY_PATH等,确保Chromedriver能找到依赖库。

2. 并发启动资源竞争问题

多进程同时启动Chromedriver可能触发系统资源限制或端口冲突:

  • 限制进程池的并发数,比如mp.Pool(processes=4)(根据机器CPU核心数调整,不要一次性启动过多进程),避免瞬间占用过多内存、CPU或端口;
  • 给每个Chromedriver实例指定单独的端口,通过options.add_argument(f'--remote-debugging-port={port}'),端口可以用动态生成的(比如从9222开始递增,确保不重复)。

3. Chromedriver启动权限与依赖问题

  • 检查/usr/bin/chromedriver的执行权限,确保cron用户拥有可执行权限:ls -l /usr/bin/chromedriver,如果权限不足,执行sudo chmod +x /usr/bin/chromedriver;
  • 手动在cron环境下测试Chromedriver能否单独启动:写一个简单的测试脚本,用cron调度执行,输出详细日志,看是否有依赖缺失的提示(比如libnss3等库),Ubuntu下可以通过apt install libnss3 libgconf-2-4 libatk-bridge2.0-0 libcups2 libxkbcommon0补全常见依赖。

4. 日志与调试优化

  • 在wait_book_page函数中,捕获Chromedriver启动时的标准输出和错误,Selenium的Service类可以设置日志输出:
    webdriver_service = Service('/usr/bin/chromedriver')
    webdriver_service.log_path = '/home/***/chromedriver.log'
    driver = webdriver.Chrome(service=webdriver_service, options=options)
    
    这样能看到Chromedriver启动失败的具体原因,而不是只看到Selenium抛出的通用错误;
  • 在crontab中增加更详细的日志,比如把环境变量也输出到日志:59 8 * * * username env >> /home/***/env.log && source /home/***/.bashrc && DISPLAY=:0 /home/***/miniconda3/bin/python /home/***/main.py >> /home/***/out.log 2>&1,对比手动执行和cron执行的环境变量差异。

5. 超时机制与进程清理问题

  • 当前func_timeout的超时处理中,如果Chromedriver启动失败,可能没有正确清理残留进程,导致后续启动受影响;在wait_book_page的异常块中,确保即使driver未成功初始化,也尝试清理相关进程;
  • 可以在脚本开头添加清理残留Chromedriver进程的逻辑,比如执行ps aux | grep chromedriver | grep -v grep | awk '{print $2}' | xargs kill -9(注意只清理当前脚本产生的进程,避免误杀其他进程)。

内容的提问来源于stack exchange,提问作者Hibanana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 19:44:56