爬虫 429 Too Many Requests:判断频率还是代理 IP 池
爬虫遇到 429 Too Many Requests 时,先固定账号和代理出口做降频实验,再以低频基线更换代理 IP,区分频率、配额和代理 IP 池问题。
遇到 429,先固定账号、URL、Header、Cookie 和代理 IP,只降低并发、延长请求间隔并遵守 Retry-After;如果 429 稳定下降,优先处理频率或账号/API 配额。只有在低频基线下,错误仍稳定集中于少数出口,才继续检查代理 IP 池质量、地区识别或出口复用。
先保存 429 的完整证据
429 表示请求过多,但限制维度可能是账号、API 密钥、接口、IP、设备或多项组合。保存:
- 状态码与响应体摘要;
Retry-After和其他限流响应头;- 账号/API 密钥的脱敏标识;
- URL、接口、请求方法和参数摘要;
- 并发数、请求间隔、时间窗口;
- 代理出口 IP、国家/城市;
- 请求总数、成功数、429 数量和耗时。
如果响应中包含 X-RateLimit-Limit、X-RateLimit-Remaining 或 X-RateLimit-Reset 等字段,也应一并保存;这些字段有助于判断限制是按账号、接口还是时间窗口计算。
HTTP 429 与 Retry-After 的语义可参考 RFC 6585 第 4 节。服务端没有义务说明采用哪一种计数维度,因此需要对照实验。
若同时出现 403 或验证码,可结合爬虫 403/429/验证码排查分开记录,避免把不同错误合并成 429。
阶段 A:固定代理 IP,逐步降低请求频率
保持账号、代理 IP、URL、Header、Cookie 和请求参数不变,按阶梯降低并发和请求频率。每一档使用相同样本量与观察时间,不要在中途换出口。
示例记录表:
| 组别 | 并发 | 请求间隔 | 请求数 | 429 数 | 成功数 | 结论 |
|---|---|---|---|---|---|---|
| A1 | 当前值 | 当前值 | 同样本量 | 记录 | 记录 | 基线 |
| A2 | 降低一档 | 延长一档 | 同样本量 | 记录 | 记录 | 与 A1 比较 |
| A3 | 再降低一档 | 再延长一档 | 同样本量 | 记录 | 记录 | 验证趋势是否重复 |
若降频后 429 在连续时间窗口内都明显下降,而出口未变,主要矛盾更可能是频率、账号或接口配额。若响应带 Retry-After,等待时间应优先遵守服务端提示。
阶段 B:保持低频基线,仅更换代理 IP
保持阶段 A 得到的低频基线,固定账号、URL、Header、Cookie、参数、并发和间隔,只替换同地区代理 IP。
| 结果模式 | 更可能的原因 | 下一步 |
|---|---|---|
| 所有出口在同一时段都 429 | 账号、接口或全站限流 | 暂停并检查配额/服务端提示 |
| 同一账号跨多个出口都 429 | 账号或 API 密钥配额 | 换 IP 通常无效 |
| 少数出口跨账号重复 429 | 出口复用或质量问题 | 隔离出口并扩大同地区样本 |
| 更换出口短暂恢复,随后再次 429 | 频率策略仍不合适 | 回到阶段 A,降低总体负载 |
| 429 响应实际是验证页面 | 状态分类错误 | 单独记录验证码/挑战,不当作普通 429 |
429 的重试与停止规则
429 响应的基础退避代码
```python
import random
import time
def wait_before_retry(response, attempt):
retry_after = response.headers.get("Retry-After")
if retry_after and retry_after.isdigit():
wait = float(retry_after)
else:
wait = min(2 ** attempt, 60)
time.sleep(wait + random.uniform(0, 0.5))
```
生产环境如何设置重试上限与共享限流
生产实现还应支持 HTTP 日期格式的 Retry-After,并设置:
1. 最大重试次数;
2. 单任务总时限;
3. 同账号或接口的共享限流器;
4. 连续 429 后的暂停和报警;
5. 重试队列的容量上限。
不要让多个工作进程各自判断后立即重试,否则总体流量仍可能超过限制。账号或 API 密钥维度的限流,应在所有工作进程之间共享状态。
把 403、429、验证码和空结果分开
| 结果 | 主要含义 | 是否按 429 重试 |
|---|---|---|
| 429 | 请求过多或配额限制 | 按服务端提示有限重试 |
| 403 | 权限、账号、地区或访问策略 | 不直接套用 429 退避 |
| 验证码/挑战页 | 环境、会话或请求行为变化 | 暂停并单独诊断 |
| HTTP 200 但空结果 | 业务无数据或解析问题 | 不应计为请求成功或 429 |
| 5xx | 临时服务端错误 | 可有限重试,单独统计 |
把所有失败合并为一个错误率,会导致错误扩容代理 IP 池或错误提高重试次数。
建议把每个实验窗口固定为相同请求数,例如每组 100 次,并记录窗口开始和结束时间。只有在多个窗口都出现同样趋势时,才把“降频有效”或“少数出口异常”当作可复用结论。
评估代理 IP 池容量的方法
评估代理 IP 池容量时,应使用单个代理 IP 的安全承载量、基线成功率、冷却占比和重试放大,而不是用“总请求量÷IP 数”直接估算。
用脱敏复测数据区分频率限制与代理池因素
以下为脱敏记录示例(接口、账号和 IP 已隐去,数字为示例、非 SLA):同一账号与单一出口、并发 5 时 50 次请求出现 429 12 次;降至并发 1、间隔 8 秒后为 2 次;保持低频改用 5 个出口仍为 2 次。该对照更支持频率因素,不能据此断言代理池无问题。
429 状态码与 Retry-After 可核对 RFC 6585,HTTP 语义可核对 RFC 9110;并发、间隔和样本量属于经验设计。
FAQ
429 和 403 是同一种问题吗?
不是。429 主要表示请求过多或配额限制;403 还可能涉及权限、账号、地区或访问策略。
没有 Retry-After 怎么办?
采用指数退避和随机抖动,并设置最大次数与任务总时限。仍持续 429 时暂停任务。
账号配额会导致 429 吗?
会。若限制绑定账号或 API 密钥,更换代理 IP 通常不会解除配额限制。
单次 429 能判断代理 IP 池质量吗?
不能。至少要完成降频实验,并在低频基线下比较多个同地区出口和时间窗口。
确认问题确实集中在出口后,再按任务规模评估动态住宅代理 IP。
