requests.get() 必须显式设置timeout,推荐拆分为connect和read两部分:timeout=(3, 7),即连接超时3秒、读取超时7秒,兼顾响应速度与稳定性。

requests.get() 的 timeout 参数到底怎么设才不翻车
超时不是设得越长越好,也不是随便写个 timeout=10 就万事大吉。requests 默认不设超时,一旦目标服务器卡住或网络中断,你的爬虫可能在那干等几分钟甚至更久,进程卡死、线程堆积、任务积压全跟着来。
必须显式传 timeout,而且要拆成连接超时(connect)和读取超时(read)两部分——这是最常被忽略的关键点:
-
timeout=(3, 7)表示:最多等 3 秒连上服务器,连上后最多再等 7 秒收完响应体 - 只写
timeout=10是等价于timeout=(10, 10),连接慢但响应快的站点会白白多等几秒 - 内网或本地测试可设短些(如
(1, 3)),公网爬取高延迟站点建议(5, 15)起步,再按实际日志调优
捕获 requests.exceptions.Timeout 而不是用 try-except 包所有异常
超时错误必须单独处理,混在通用异常里会掩盖真实问题。比如 DNS 解析失败、连接被拒绝、SSL 握手失败,这些都不是超时,但都抛 requests.exceptions.RequestException,和 Timeout 混在一起就难定位。
正确做法是分层捕获:
try:
resp = requests.get(url, timeout=(3, 7))
resp.raise_for_status()
except requests.exceptions.Timeout:
# 这里专门处理超时:重试?换代理?记日志?
log_error(f"Timeout on {url}")
except requests.exceptions.HTTPError as e:
# 状态码非 2xx,比如 403、502
pass
except requests.exceptions.ConnectionError:
# DNS 失败、拒绝连接、无网络等
pass
requests.Session() 配置全局 timeout 仍需单次覆盖
很多人以为给 Session 设了 timeout 就一劳永逸,其实 requests 的 Session 并不支持全局默认 timeout 参数。你不能写 s = requests.Session(timeout=(3, 7))——这会直接报错 TypeError。
可行方案只有两个:
- 每次调用
s.get()或s.post()时手动传timeout参数 - 封装一层请求函数,统一注入 timeout,并预留 override 接口:
def safe_get(url, timeout=(3, 7), **kwargs): return requests.get(url, timeout=timeout, **kwargs)
别信网上那些“设置 Session 默认超时”的代码片段,基本都是错的或已过时。
超时 + 重试组合使用时,注意指数退避和最大重试次数
单纯加 timeout 只防卡死,不解决偶发性网络抖动。配合重试才有实际鲁棒性,但乱 retry 会加重目标压力,也可能触发风控。
推荐用 urllib3.util.Retry 配合 requests.adapters.HTTPAdapter:
from urllib3.util.retry import Retry
import requests
<p>retry_strategy = Retry(
total=3,
status_forcelist=[429, 500, 502, 503, 504],
method_whitelist=["HEAD", "GET", "OPTIONS"],
backoff_factor=1 # 第一次重试延 1s,第二次 2s,第三次 4s
)
adapter = requests.adapters.HTTPAdapter(max_retries=retry_strategy)
session = requests.Session()
session.mount("http://", adapter)
session.mount("https://", adapter)</p><h1>后续 session.get() 仍需显式传 timeout!</h1><p></p>
注意:retry 不会自动重试超时错误(Timeout 属于 ConnectTimeout 或 ReadTimeout,不在 status_forcelist 范围内),所以 timeout 和 retry 是正交机制,缺一不可。
真正容易被忽略的是:超时值要略小于重试间隔,否则可能刚到 timeout 就触发 retry,紧接着又 timeout,形成高频无效请求。比如 backoff_factor=1 时,别把 timeout 设成 (1, 1)。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











