scrapy中拦截404、503等状态码需在downloader_middlewares中靠前位置(priority

中间件里怎么拦截 404、503 这类状态码?
Scrapy 的 HttpErrorMiddleware 默认会把非 200 响应(如 404、500、503)直接丢进 errback 或终止请求,但你往往需要统一处理——比如记录、重试、或转成正常响应。关键不是关掉它,而是用自定义中间件在它之前或之后介入。
推荐做法:在 DOWNLOADER_MIDDLEWARES 中靠前位置插入自定义中间件,检查 response.status,对目标状态码做干预:
- 若想让 404 当作正常响应继续走
parse,就别调raise IgnoreRequest,直接 return response - 若需重试 503,可修改
response.request的meta并 return 给调度器重新入队 - 避免在中间件里直接调
retry方法——那是RetryMiddleware的职责,重复逻辑易冲突
如何让中间件区分“要忽略”和“要重试”的状态码?
硬编码判断太脆弱,建议用配置驱动。在 settings.py 中定义:
HTTP_STATUS_IGNORE = [401, 403, 410] HTTP_STATUS_RETRY = [502, 503, 504]
然后中间件里读取:
```python
def process_response(self, request, response, spider):
if response.status in self.ignore_statuses:
raise scrapy.exceptions.IgnoreRequest(f"Ignored {response.status}")
if response.status in self.retry_statuses:
reason = f"HTTP {response.status}"
return self._retry(request, reason, spider)
return response
```
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
注意:self._retry() 要从 scrapy.downloadermiddlewares.retry.RetryMiddleware 复制逻辑,或直接调用其 retry 方法(需传入正确参数),否则重试不生效。
为什么开了 HttpErrorMiddleware 还收不到 404 的 response?
因为默认开启的 HttpErrorMiddleware 在中间件链中位置靠后(默认 priority=500),且它检测到非 200 就直接 raise HttpError,导致你的自定义中间件根本收不到 response。解决方法只有两个:
- 把你的中间件 priority 设得比 500 小(比如 400),确保它先拿到 response
- 或者干脆关掉
HttpErrorMiddleware:'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware': None
选后者更干净——毕竟你要自己处理状态码,留着它反而多一层干扰。
中间件里改 response.status 有用吗?
没用。Scrapy 的 response.status 是只读属性,强行赋值会静默失败或抛 AttributeError。真要“伪装”状态码(比如把 503 当 200 用),只能靠绕过校验逻辑,例如:
- 在中间件里 return 一个新
HtmlResponse,status 设为 200,body 复用原 response.body - 但要注意:原 response.headers、url、encoding 等字段也要手动复制,否则解析可能出错
- 这种做法会丢失原始状态信息,调试时容易困惑,除非业务强要求,否则不建议
真正该关注的是:哪些状态码意味着数据不可用(如 410)、哪些只是临时抖动(如 503)、哪些要告警(如 429)。中间件只是执行层,判断逻辑得落在配置和业务语义上。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










