APScheduler启动爬虫常卡住或不执行,因默认后台线程随主线程退出而终止;须用BlockingScheduler并调用start()阻塞主线程,或显式保持主线程存活。

为什么直接用 APScheduler 启动爬虫常卡住或不执行
常见现象是:脚本运行后立即退出,或者日志里没看到任务触发记录。根本原因在于 APScheduler 的调度器默认以「后台线程」方式运行,主线程结束,整个进程就退出了——爬虫根本没机会跑。
必须显式阻塞主线程,让它持续存活。最稳妥的做法是用 BlockingScheduler,而不是 BackgroundScheduler(后者适合嵌入已有长时服务中)。
- 用
BlockingScheduler时,调用scheduler.start()就会一直阻塞,不再往下执行 - 若需在启动后做其他初始化(比如加载配置),务必放在
scheduler.start()之前 - Windows 下若用
asyncio事件循环,注意AsyncIOScheduler需搭配asyncio.run(),不能混用阻塞式写法
如何让定时任务真正“按秒/分/小时”精准触发
APScheduler 默认使用 date、interval、cron 三种触发器,但新手常误以为 interval=60 就等于“每分钟执行一次”,其实它表示“每次执行完后等 60 秒再执行下一次”——如果某次爬虫耗时 45 秒,那下次实际间隔只有 15 秒。
要严格按钟表时间对齐(例如整点、每 5 分钟),必须用 cron 触发器:
scheduler.add_job(
crawl_func,
'cron',
minute='*/5', # 每5分钟的第0秒触发(如 00:00, 00:05, 00:10...)
second='0' # 强制在每分钟第0秒开始,避免漂移
)
-
cron支持标准 Linux cron 表达式,但注意APScheduler不支持@reboot或@yearly这类别名 - 若用
interval,想控制最大延迟,可加max_instances=1防止任务堆积 - 生产环境建议加
coalesce=True,避免因调度器重启导致错过的任务被批量补跑
爬虫函数里怎么安全处理异常,避免调度器崩溃
如果爬虫函数内抛出未捕获异常(比如 requests.exceptions.ConnectionError),APScheduler 默认会记录错误并继续下一次调度——这看似正常,但容易掩盖问题:你可能根本没注意到日志里滚动着大量报错,直到数据断更一天才发现。
正确做法是在任务函数内部兜底,并主动记录关键状态:
def crawl_func():
try:
response = requests.get('https://example.com', timeout=10)
response.raise_for_status()
parse_and_save(response.text)
except requests.RequestException as e:
logger.error(f"Request failed: {e}")
except Exception as e:
logger.critical(f"Unexpected error in crawl: {e}", exc_info=True)
- 不要依赖调度器自动重试——它不会帮你重试失败的任务,除非你手动实现重试逻辑
- 避免在任务中直接调用
sys.exit()或os._exit(),会导致整个调度器退出 - 若需根据返回内容决定是否跳过本次保存(比如页面未更新),应返回明确的状态码或标记,而非抛异常
部署时为什么日志不输出、数据库连接失败
本地测试通过,一放到服务器(尤其是 systemd 或 Docker)就出问题,大概率是路径和环境没对齐:
- 相对路径(如
'./data/output.json')在 systemd service 里默认工作目录是/,不是你的项目根目录——必须用绝对路径或os.path.dirname(__file__)动态拼接 - 数据库连接池(如
SQLAlchemy)若没设pool_pre_ping=True,长时间空闲后首次查询易报Lost connection to MySQL server - Linux 系统限制用户级定时任务数,默认
MaxTasksPerChild可能影响BlockingScheduler的稳定性,建议在 systemd unit 文件里加TasksMax=infinity
最易被忽略的是信号处理:BlockingScheduler 默认响应 SIGINT(Ctrl+C)和 SIGTERM,但某些容器环境发送的是 SIGHUP,导致无法优雅关闭——需要手动添加信号监听。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











