scrapy中应在downloadermiddleware的process_exception(捕获网络异常)和process_response(检查状态码)中分别处理临时错误并重试,需显式构造新request、更新retry_times、动态更换user-agent且优先级设为300以避免与内置retrymiddleware冲突。

中间件里怎么捕获并重试失败的请求?
Scrapy 的 DownloaderMiddleware 是处理异常请求的核心位置,但直接在 process_response 或 process_exception 里写重试逻辑容易漏掉重定向、超时、连接拒绝等不同错误类型。关键不是“能不能重试”,而是“在哪重试、重试几次、要不要改请求参数”。
常见错误现象:请求返回 503 或抛出 Twisted TimeoutError,但默认中间件不重试,爬虫直接跳过该 URL;或者手动调用 retry() 后没更新 Request.meta,导致无限重试或重试次数失控。
-
process_exception只捕获 downloader 层抛出的异常(如网络断开、DNS 失败),不捕获 HTTP 状态码异常(如 403/500)——后者得靠process_response判断response.status - 重试必须显式构造新
Request并设置meta['retry_times'],否则 Scrapy 不知道这是重试请求,也无法触发内置重试逻辑 - 建议在重试前加随机延迟(
time.sleep(random.uniform(1, 3))),避免被目标站点封 IP,尤其在并发高时
如何让中间件区分临时性错误和永久性错误?
不是所有失败都要重试。比如 404 是永久性错误,重试没意义;而 503、502、连接超时(Twisted ConnectionLost)才是典型临时错误。中间件需要按错误类型分流处理。
实际操作中,靠 response.status 和异常类型双判断最稳妥。只看状态码会漏掉 DNS 解析失败这类无响应情况;只捕异常又无法识别服务端主动返回的错误码。
- 在
process_response中检查response.status in [500, 502, 503, 504],满足则调用self._retry_request(request, spider) - 在
process_exception中用isinstance(exception, (TwistedTimeoutError, ConnectionRefusedError, DNSLookupError))判断临时异常 - 对
403可单独处理:添加 headers 或更换 user-agent,而不是简单重试
自定义中间件怎么避免和 Scrapy 内置重试机制冲突?
Scrapy 默认启用了 RetryMiddleware(优先级 500),如果你的中间件优先级设为 500 或更低,它会在内置重试之后执行,导致重复重试或覆盖原有重试计数。正确做法是把自定义中间件设为更高优先级(数值更小),让它先介入。
配置位置在 settings.py:DOWNLOADER_MIDDLEWARES 字典的 value 就是优先级。值越小越早执行。
- 推荐设为
300或200,确保你的逻辑在RetryMiddleware(500)之前运行 - 禁用默认重试:设
RETRY_ENABLED = False,否则你手动重试 + 内置重试叠加,可能超出预期次数 - 重试次数统一由
request.meta.get('retry_times', 0)控制,每次重试需递增该值,并与RETRY_TIMES配置比对
为什么重试后请求还是 403?中间件里怎么动态换 User-Agent?
很多反爬站点只拦固定 UA,重试时不换头,等于反复撞墙。中间件里不能只重试,还得动态注入新 UA —— 但要注意别污染原始请求的 headers 字段。
安全做法是深拷贝原始 headers,再更新 User-Agent,而不是直接修改 request.headers。否则后续中间件或 downloader 可能复用已被篡改的 headers。
- 用
request.replace(headers=request.headers.to_dict().copy())获取可修改副本 - 从 UA 池随机选一个:
random.choice(['Mozilla/5.0 (X11; Linux x86_64) ...', ...]) - 记得把新 UA 写进新 Request 的
headers,同时保留原meta(含retry_times、download_timeout等)
真正麻烦的是 UA 被识别出是爬虫库生成的特征字符串,这时候光换 UA 不够,得配合代理、JavaScript 渲染或真实浏览器指纹——但那是另一个层面的事了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











