502错误表明目标服务器网关无法从上游服务获取响应,通常因对方服务过载、部署中或崩溃所致,与反爬无关;应优先验证服务状态,配置指数退避重试(total=3, status_forcelist=[502,503,504], backoff_factor=1),避免盲目换头、加代理或高频重试。

502错误是服务端挂了,不是你代码写错了
遇到 502 Bad Gateway,第一反应不该是改请求头或重写解析逻辑——这错误说明目标服务器的网关(比如Nginx)没法从上游(比如后端Python服务)拿到响应,大概率是对方服务临时过载、部署中、或进程崩了。你的爬虫没被封,但此刻发请求等于往关机的路由器上拨号。
- 别急着换
User-Agent或加代理:502 和反爬无关,伪装再好也连不上死掉的 upstream - 检查是否全量报 502:如果只有某个接口/路径稳定返回 502,可能是该服务模块宕机,不是整个站挂了
- 用浏览器或
curl -I https://example.com/api手动验证,确认是不是真挂了——避免误判成自己网络问题
requests重试必须带退避(backoff),不能死循环冲
直接套 while True + try/except 是最常见翻车点:既可能把重试压成 DoS,也可能在服务恢复前耗尽连接池或触发风控。要用指数退避,且限定总尝试次数和超时。
- 用
urllib3.util.Retry配合requests.adapters.HTTPAdapter,别手写重试逻辑 - 关键参数:
total=3(总重试次数)、status_forcelist=[502, 503, 504](只对网关类错误重试)、backoff_factor=1(第一次等1s,第二次2s,第三次4s) - 避免设
backoff_factor > 2:退避太激进会导致爬取节奏断层,尤其批量任务里容易拖慢整体进度
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retry_strategy = Retry(
total=3,
status_forcelist=[502, 503, 504],
backoff_factor=1
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("http://", adapter)
session.mount("https://", adapter)
访问频率控制不是“每秒1次”就安全
封IP往往不看绝对QPS,而看单位时间内的请求密度+行为特征。比如连续10秒每秒1次,比匀速每3秒1次更容易触发风控;带登录态的请求还可能被关联设备指纹。
- 用
time.sleep()硬等不如用random.uniform(2.5, 4.0):加抖动能显著降低模式识别概率 - 别只控单个IP的频率:如果你用代理池,确保每个代理的请求数/间隔也独立计算,否则代理IP会集体暴雷
- 注意 DNS 缓存影响:
requests默认复用连接,高频换 Host 可能导致底层 socket 复用异常,间接引发 5xx ——必要时加session.close()或设Connection: closeheader
502和IP被封的边界其实很模糊
有些WAF(比如Cloudflare)在上游不可用时会返回 502,但同时悄悄记录你的请求特征;如果紧接着又出现大量 403 或 429,说明你已经进入观察名单——502 只是表象,背后可能已埋雷。
- 日志里别只记状态码:务必同时记
response.headers.get("Server")和response.headers.get("CF-RAY")(如果有),这是判断是否经过 Cloudflare 的关键线索 - 发现连续多个 502 后,暂停该域名所有请求至少 5 分钟:既是给服务喘息,也是规避“持续探测”嫌疑
- 真实环境中,502 后立刻切代理/IP 很危险——新IP没历史行为,反而更易被标记为异常流量
真正麻烦的不是 502 本身,而是它常和下游服务不稳定、前端CDN配置错误、甚至你自己的DNS解析缓存混在一起。先确认错误源头在哪,再决定是等、是调参、还是换路子。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











