Scrapy代理407不自动重试怎么办?从默认状态码到认证刷新逐层修复
悟空代理IP 2026-09-15 159
Scrapy 代理返回 407 Proxy Authentication Required 后没有自动重试,通常不是 RetryMiddleware 失效。Scrapy 当前官方文档列出的默认 RETRY_HTTP_CODES 包含 500、502、503、504、522、524、408 和 429,并不包含 407。因此,请求会沿响应链继续处理,最终可能被 HttpErrorMiddleware 忽略;如果只看 Item 数量,就容易把认证失败误判成“页面漏爬”。
修复也不应只做一件事。407 表示代理入口已经响应,但认证没有通过;先确认账密、白名单和订单状态,再决定是否刷新认证并有限重试。对同一份错误凭据无限重放,不会提高成功率,反而会放大任务量和日志噪声。以下方法仅用于团队自有端点、公开许可页面或已获得授权的采集任务。
先确认失败确实发生在代理层
| 现象 | 所在层级 | 优先检查 |
|---|---|---|
| 407 | 代理入口认证 | 用户名密码、来源公网 IP 白名单、套餐状态、认证头 |
| 401 或 403 | 目标服务授权 | 登录态、接口权限、访问规则 |
| 429 | 目标服务限流 | 总请求速率、并发、恢复时间 |
| DNS、连接或 TLS 异常 | 网络链路 | 主机、端口、协议、防火墙和证书 |
先把并发降到 1,并使用团队控制的健康检查地址复现。日志只记录请求编号、代理资源别名、状态码、retry_times、耗时和配置版本,不要输出完整代理地址、用户名、密码、Cookie 或业务响应正文。需要核对代理字段时,可参考代理IP地址和端口配置指南。
为什么把 RETRY_TIMES 调大仍然没用
RETRY_TIMES 只限制“已经被判定为可重试”的请求次数。407 不在默认状态码列表中,所以把次数从 2 改成 5,并不会让默认 RetryMiddleware 接管它。还要检查单个请求是否设置了 request.meta["dont_retry"] = True;Scrapy 官方文档明确说明,这会让 RetryMiddleware 忽略该请求。
最直接的配置可以把 407 加入列表:
# settings.py;以下列表按项目锁定的 Scrapy 版本核对
RETRY_HTTP_CODES = [500, 502, 503, 504, 522, 524, 408, 429, 407]
RETRY_TIMES = 2
但这只适合认证信息会在下一次请求前自动更新的场景,例如短期凭据由受控组件刷新,或者白名单变更正在按明确时限生效。若账密写死且已经失效,加入 407 只会重复失败。升级 Scrapy 时应重新对照官方 RetryMiddleware 文档,不要长期复制一份无人维护的默认列表。
更稳妥:只在认证刷新成功后重试一次
生产项目更适合用独立下载中间件处理 407:发现认证失败后调用内部凭据提供器,拿到新配置才生成一次重试请求;刷新失败则保留原响应并报警。Scrapy 的 process_response() 可以返回一个 Request,框架会停止当前响应链并重新调度该请求。
# middlewares.py
from scrapy.downloadermiddlewares.retry import get_retry_request
class ProxyAuth407Middleware:
def process_response(self, request, response, spider):
if response.status != 407:
return response
refreshed = spider.crawler.proxy_credentials.refresh(
resource_id=request.meta.get("proxy_resource_id")
)
if not refreshed:
spider.crawler.stats.inc_value("proxy_auth/refresh_failed")
return response
refreshed_headers = request.headers.copy()
refreshed_headers.update(refreshed.safe_headers)
retry_request = request.replace(headers=refreshed_headers)
retry_request.meta["proxy_auth_refresh_times"] = (
request.meta.get("proxy_auth_refresh_times", 0) + 1
)
return get_retry_request(
retry_request,
spider=spider,
reason="proxy_auth_407",
max_retry_times=1,
stats_base_key="proxy_auth_retry",
) or response
注意:Scrapy 原生不提供 crawler.proxy_credentials、refresh() 或 safe_headers;它们是示例中的项目自定义凭据提供器接口,需要由团队按自己的密钥系统实现。返回值只向中间件提供可安全写入请求的认证头,不应把真实凭据硬编码到代码或普通日志。启用中间件时把它放在内置 RetryMiddleware 与 HttpProxyMiddleware 之间,并在项目锁定版本中核对顺序:
DOWNLOADER_MIDDLEWARES = {
"myproject.middlewares.ProxyAuth407Middleware": 740,
}
官方设置文档显示,内置 RetryMiddleware 默认顺序为 550,HttpProxyMiddleware 为 750;响应阶段按相反顺序执行。顺序配置错误时,自定义中间件可能看不到预期状态,或者出现两层重试叠加。若已经由自定义中间件处理 407,就不要再把 407 加入全局 RETRY_HTTP_CODES。
避免认证刷新演变成重试风暴
第一,为 407 单独设一次重试预算,不与连接超时、5xx 共用模糊的“失败就重试”规则。第二,多个并发请求同时收到 407 时,凭据刷新应使用锁或 single-flight 机制,只允许一个任务更新,其余任务等待同一结果。第三,认证连续失败要触发熔断,暂停领取新任务,而不是让每个请求各自刷新。
还要让统计能回答三个问题:407 有多少、刷新成功多少、刷新后恢复多少。至少观察 downloader/response_status_count/407、自定义 proxy_auth/refresh_failed、proxy_auth_retry/reason_count/proxy_auth_407 和最终 Item 完成量。若刷新成功但仍是 407,优先核对白名单看到的公网出口、凭据所属订单和代理协议,不要继续扩大并发。
上线前做四组故障演练
在自有测试环境分别验证:正常凭据一次成功;失效测试凭据返回 407 且最多重试一次;刷新服务不可用时请求停止并报警;目标返回 401、403 或 429 时不会进入代理认证重试。再检查关闭 Spider 前的统计汇总,确认失败任务可追踪、可回放,且日志中没有秘密。
Scrapy代理407不自动重试的关键,不是简单调大次数,而是先理解默认状态码范围,再把“认证刷新”和“请求重放”绑定成一次受控动作。若团队还需要统一管理隧道入口、会话和并发,可查看悟空代理隧道代理IP说明,并以当前文档和实际订单约定为准。

