tenacity.retry 比手写 while 循环更可靠,因其内置对 Timeout、ConnectionError 等网络异常的精准分类支持,能区分可重试与不可重试错误,并提供退避策略、动态参数传递和上下文记录等完备机制。

tenacity.retry 为什么比手写 while 循环更可靠
手写重试容易漏掉网络异常的细分类型,比如 requests.exceptions.Timeout 和 requests.exceptions.ConnectionError 表现不同,但都该重试;而 tenacity 内置了对常见异常的精准分类支持,还能区分“值得重试”和“直接失败”的错误。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
retry=retry_if_exception_type((requests.exceptions.Timeout, requests.exceptions.ConnectionError))明确指定重试范围,别用Exception一锅端 - 避免在重试装饰器里包裹整个爬虫主逻辑(比如含登录、解析、存库),只包发请求那一步——否则一次解析失败也会触发重试,浪费资源
-
tenacity默认不捕获KeyboardInterrupt,但你在调试时 Ctrl+C 中断后,它可能还在默默重试,加stop=stop_after_attempt(3)配合retry_error_callback可快速响应中断
退避策略选 exponential 还是 fibonacci?
两种都是退避,但行为差异直接影响请求成功率和服务器压力。exponential 是 1s → 2s → 4s → 8s,fibonacci 是 1s → 1s → 2s → 3s → 5s,后者前期更激进,适合短时抖动;前者压峰更稳,适合高并发或目标站限流严的场景。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 默认从
wait=wait_exponential(multiplier=1, min=1, max=10)开始调,min防止首重试太快被封,max防止等太久卡住 - 别设
multiplier=0.1试图“更快重试”——实际会变成 0.1s → 0.2s → 0.4s,反而更容易触发目标站的频率拦截 - 如果目标接口明确返回
429 Too Many Requests,优先用retry_if_result+ 响应状态码判断,比单纯等时间退避更准确
@retry 装饰器怎么传入动态参数(比如当前 URL 或 headers)
装饰器在函数定义时就固定了参数,没法自动感知每次调用的 url 或 headers。硬塞进去会导致所有重试共用同一套参数,出错时连日志都难定位。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 把请求逻辑单独抽成函数,用
@retry包它,参数通过闭包或函数参数自然传递,例如:@retry(stop=stop_after_attempt(3)) def fetch_url(url, headers=None): return requests.get(url, headers=headers, timeout=5) - 需要记录每次重试的上下文(比如第几次、当前 URL),用
before=before_log(logger, logging.DEBUG)或自定义before回调,别往装饰器里塞 print - 避免在装饰器参数里写死
url="https://example.com"—— 这会让装饰器绑定到一个地址,其他调用全失效
重试后 response.status_code == 403 怎么办
403 不是网络异常,是服务端明确拒绝,tenacity 默认不重试它。但有些站点会因 User-Agent 缺失、Cookie 过期或 Referer 校验失败返回 403,这类问题重试本身没用,必须改请求条件。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 先确认是不是真 403:打印
response.headers.get("Server")和response.text[:200],有时是 WAF 返回的伪装 403 页面 - 不要靠增加重试次数解决 403,而是检查
headers是否含有效User-Agent、是否需维持session.cookies、是否漏了Referer - 若必须重试 403(比如登录态偶发失效),用
retry_if_exception_type+ 自定义判断函数,但务必加stop=stop_after_delay(30)防止无限循环
真正麻烦的是混合场景:一次请求既可能超时又可能返回 403,还可能中间重定向失败。这时候得拆开处理——网络层用 tenacity 保底,业务层用状态码分支兜底,别指望一个装饰器解决所有问题。










