代理返回 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,它是代理发的,不是你访问的网站发的。两种情况会撞上:

  1. 你用的是白名单模式,但这条线路要求账号密码——反之也一样;
  2. 账号密码写错了,或者密码里有 @、: 这类字符没做 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 是最需要分情况的一个。我的排查顺序是:

  1. 用一个回显 IP 的地址(比如 http://httpbin.org/ip)走代理访问一次,看返回的是不是代理的出口 IP;
  2. 如果回显的还是你本机 IP,说明代理压根没生效——检查 proxies 参数、环境变量、以及取 IP 的请求是不是被误配了代理;
  3. 如果回显是代理 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 不在白名单列表"以及还剩多少秒),排查时省了不少事。即然要做采集,把这几类错误分开埋点,后面看监控就能一眼看出是线路问题还是目标站问题。