代理返回 407、406、403、超时,分别怎么排查
采集出问题的时候,最费时间的不是改代码,而是判断错误到底出在哪一层。同样一个 403,可能是白名单没生效,也可能是目标站把你拦了,处理方式完全相反。这篇整理了我在实际项目里遇到过的几类错误,以及对应的排查顺序。
第一步:先分清错误是谁返回的
这是最关键的一步。同一个数字,来源不同含义就不同:
- 代理层返回:407、502、504,以及提取接口自己的 status 字段;
- 目标站返回:403、404、429、503;
- 本机网络层:连接超时、连接被重置、DNS 解析失败。
怎么分?看响应体和响应头。代理层返回的错误通常是它自己拼的一小段 HTML 或纯文本,没有目标站的 Server、Set-Cookie 这些头。把响应体前 200 个字符打出来看一眼,心里就有数了。
逐条对照表
| 现象 | 含义 | 怎么处理 |
|---|---|---|
| 407 | 代理层要账号密码 | 这条线路和你的认证方式不匹配,换一条 IP 重试 |
| 406(提取接口 status) | 提取太频繁 | 改成批量提取,单次 10~20 条 |
| 403 | 白名单未生效,或目标站反爬 | 先验证出口 IP,再判断是不是目标站 |
| 502 / 504 | 代理节点到目标站这一段出问题 | 换 IP;持续出现就换个目标域名试试 |
| 连接超时 | 代理端口连不上,或目标站不可达 | 换 IP + 缩短超时时间 |
| 连接被重置 | 中间设备掐断,或目标站主动断开 | 降并发、加请求头、换 IP |
407:代理层说"你得先证明自己有权限"
407 的全名是 Proxy Authentication Required,它是代理发的,不是你访问的网站发的。两种情况会撞上:
- 你用的是白名单模式,但这条线路要求账号密码——反之也一样;
- 账号密码写错了,或者密码里有
@、:这类字符没做 URL 编码。
处理起来很简单:当成失败,换一条 IP 重试。我在示例代码里都是这么写的,因为同一批提取出来的线路偶尔会混进需要认证的节点,重试一次基本就好了。
code, body = request_via_proxy(target, proxy)
if code == 407:
# 这条线路要账号密码,换一条重试
raise RuntimeError("%s 返回 407" % proxy)
406:提取接口在提醒你"手太快了"
提取接口通常会在响应体里带一个自己的状态码,比如 {"status":406,"msg":"提取频率过快"}。这不是网络故障,纯粹是你调用太密了。改成批量提取之后就不用管它了,具体做法在代理池设计那篇里写过。
顺便说个设计细节:有些接口在订单过期、参数错误这类无效请求上会故意延迟十几秒才返回,同时临时限制来源 IP。这不是接口坏了,而是防刷设计——防止客户端拿错参数疯狂重试把服务器打满。所以你的代码里遇到这类错误,正确做法是记日志 + 退出,而不是立刻重试。
403:先确认出口 IP 到底是谁
403 是最需要分情况的一个。我的排查顺序是:
- 用一个回显 IP 的地址(比如
http://httpbin.org/ip)走代理访问一次,看返回的是不是代理的出口 IP; - 如果回显的还是你本机 IP,说明代理压根没生效——检查
proxies参数、环境变量、以及取 IP 的请求是不是被误配了代理; - 如果回显是代理 IP 但仍然 403,就看响应体:代理层提示一般是"IP 不在白名单"这类文案,目标站的 403 则会带自己的页面和头部。
还有一种情况是目标站对 UA、Referer、Cookie 有校验。这种就不是代理的问题了,得回去补请求头。
超时类:区分"连不上"和"连上了没响应"
这两者在代码里的表现不同,处理方式也不同:
- 连接超时(connect timeout):TCP 都没握上手,代理 IP 大概率已经失效,换 IP;
- 读取超时(read timeout):连上了但对方不吐数据,可能是目标站慢,也可能是这条线路的质量差。
建议把两类超时分开设置,并且都设短一点:连接 5~10 秒,读取 10~15 秒。采集场景下,等 60 秒的收益远不如直接换一条 IP 重来。
r = requests.get(url,
proxies={"http": proxy, "https": proxy},
timeout=(6, 12)) # (连接超时, 读取超时)
一张收尾检查清单
- 取 IP 的请求是不是直连的?(容器里有没有
HTTP_PROXY环境变量) - 失败重试时有没有真的换 IP?很多重试框架默认复用同一个代理,那是白重试。
- 单 IP 并发是不是压太高了?先降到 2~5 试试。
- 超时是不是设太长?长超时会让任务队列堆积,看起来像"卡死"。
- 有没有把代理层的错误码和目标站的错误码分开统计?混在一起没法定位。
我用的线路是 星月代理,它的接口在错误信息上给得比较直白(会直接告诉你"IP 不在白名单列表"以及还剩多少秒),排查时省了不少事。即然要做采集,把这几类错误分开埋点,后面看监控就能一眼看出是线路问题还是目标站问题。