爬虫跑着跑着就断?一套 Python 爬虫稳定性排查与加固思路

举报
yd_252351073 发表于 2026/10/21 12:20:55 2026/10/21
【摘要】 长时间运行的爬虫容易卡死或崩溃。本文把中断原因分为网络异常、被限制、解析报错、进程退出四类,给出超时重试、控频、异常隔离、断点续跑和 systemd 守护的实用做法。

前言

写过爬虫的大概都遇到过这种情况:脚本刚跑起来好好的,过个把小时就卡住不动,或者直接抛异常退出,第二天一看只抓了三分之一。这篇把我自己踩过的坑整理一下,从"为什么会断"到"怎么让它断了也能接着跑",给一套能直接用的思路。

一、先搞清楚是哪种"断"

断,大致分四类,排查方向完全不同:

  1. 网络层异常:ConnectionResetError、ReadTimeout、DNS 解析失败。多半是没设超时,或者对方偶发抖动。
  2. 被目标站限制:开始返回 403、429,或者返回 200 但内容是验证页。这是频率太高或者请求特征太明显。
  3. 解析报错:页面结构变了、某条数据缺字段,None 上取属性直接崩掉整个进程。
  4. 进程本身挂了:内存涨爆被 OOM kill、SSH 断开把前台进程带走、机器重启。

建议先把日志打全:每个请求记录 URL、状态码、耗时、异常类型。跑一晚上,看日志就知道是哪一类占大头。

二、网络层:超时 + 重试 + 退避

最常见的错误是 requests.get(url) 不带 timeout,对方不回包就会一直挂着,看起来就是"卡死"。

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

session = requests.Session()
retry = Retry(
    total=5,
    backoff_factor=1,              # 1s, 2s, 4s, 8s...
    status_forcelist=[429, 500, 502, 503, 504],
    allowed_methods=["GET"],
)
session.mount("http://", HTTPAdapter(max_retries=retry))
session.mount("https://", HTTPAdapter(max_retries=retry))

resp = session.get(url, timeout=(5, 20))  # 连接 5s,读取 20s

要点:

  • 一定要设 timeout,连接和读取分开设。
  • 用 Session 复用连接,比每次新建快,也更不容易被识别。
  • 退避重试,别失败了立刻狂重试,那样只会更快被封。

三、被限制:控频比换 IP 更重要

很多人第一反应是上代理池,其实先把频率降下来,大部分问题就没了:

  • 每个请求之间加随机间隔,比如 time.sleep(random.uniform(1, 3))。
  • 并发数别开太大,单站点 2~4 个并发一般够用。
  • 带上正常的 User-Agent、Referer,别用库默认的。
  • 遇到 429 时读一下 Retry-After 头,按它说的等。

另外记得遵守目标站的 robots 协议和使用条款,别把人家服务器打挂。

四、解析层:单条失败不能拖垮全局

for item in items:
    try:
        data = parse(item)
        save(data)
    except Exception as e:
        logger.warning("parse failed: %s %s", item_url, e)
        failed.append(item_url)   # 记下来,后面单独补
        continue

解析函数里多用 .get()、判空,别默认字段一定存在。失败的 URL 单独存一份,跑完再补抓。

五、断点续跑:这才是根治

不管做得多稳,长任务总有断的时候,关键是断了能接着跑,而不是从头再来:

  • 把待抓 URL 放进队列(简单场景用 SQLite 一张表就行),字段包括 url、status(pending/done/failed)、retry_count。
  • 每抓完一条就更新状态,程序启动时只取 status='pending' 的。
  • 已抓数据按主键去重写入,重复跑也不会产生脏数据。
cur.execute("SELECT url FROM tasks WHERE status='pending' LIMIT 100")

这样哪怕进程被杀,重启后最多重复一两条。

六、进程守护

在云服务器上跑长任务,别直接前台 python spider.py:

  • 临时跑用 nohup python spider.py > spider.log 2>&1 & 或者 tmux。
  • 长期跑写成 systemd 服务,配 Restart=on-failure,挂了自动拉起:
[Service]
ExecStart=/usr/bin/python3 /opt/spider/spider.py
Restart=on-failure
RestartSec=10
  • 内存持续上涨的,检查是不是把结果全堆在列表里没落盘,或者 Session/浏览器实例没释放。用 Selenium、Playwright 的,定期重启浏览器实例。

总结

爬虫稳定性说到底就三件事:请求要有超时和重试,频率要克制,任务要能断点续跑。前两条减少断的次数,第三条让断了也不心疼。把这几块搭好,一个爬虫挂在云服务器上跑几天基本没问题。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。