代理IP用着用着就超时,惯性反应往往是"网络不好"或"IP不行",但真正的高频原因其实是:超时参数根本没设对。不设timeout的请求会挂死整个任务;一刀切的timeout会误杀慢页面、放过死地址。这篇讲timeout的分层设置实践——把超时从"报错"变成"调度信号"。
很多教程只说"设置timeout=10",于是有人写成:
```python
resp = requests.get(url, proxies=proxies, timeout=10) # 一刀切
```
问题在于这一个数字同时管了两件不同的事:
两者合理阈值差好几倍。一刀切10秒:连接卡了要等10秒才发现(浪费9秒),慢页面10秒被砍(误杀)。正确做法是分开设。
```python
# timeout=(连接超时, 读取超时)
resp = requests.get(url, proxies=proxies, timeout=(5, 15))
```
连接超时设5秒:
读取超时设15秒左右:
| 任务类型 | 连接超时 | 读取超时 | 逻辑 |
|---|---|---|---|
| 高频轻量采集(列表页) | 5秒 | 10秒 | 快进快出,失败速切 |
| 重量页面采集(详情页) | 5秒 | 20秒 | 给大页面留时间 |
| 接口轮询 | 3秒 | 8秒 | 灵敏度优先 |
| 文件下载 | 5秒 | 60秒+ | 按文件大小放宽 |
原则:连接超时全局统一(它只反映链路健康度),读取超时按任务类型分档(它反映的是页面特征)。
超时发生了,下一步的动作比超时本身更重要:
失败分类计数:每个地址维护两个计数器——连接超时次数、读取超时次数。
任务级熔断:某个目标站点的连续超时率达到30%,说明目标站点状态异常(升级风控、临时故障),整个对它的任务暂停10分钟——比一个个请求硬试高效得多。
退避重试:重试不是立即的。首先次失败等1秒,第二次等2秒,指数退避,给目标站点喘息空间。
参数改了怎么知道是变好还是变坏?看三个指标的前后对比:
1. 超时率:超时请求数 / 总请求数,调优后应下降
2. 平均响应时间:分层的timeout应让平均响应更稳定(方差变小)
3. 任务吞吐量:单位时间完成的请求数,最终目的
建议每次只调一个参数,跑一轮数据对比,确认有效再调下一个——一次全改,好坏了然但不知道该感谢谁。
Q1:timeout不设会怎样?
网络异常时请求无限等待,单个卡住的请求能堵死整个任务队列。不设timeout是任务挂死的首要原因,任何对外的请求都必须设。
Q2:连接超时和读取超时哪个更重要?
连接超时更重要——它决定故障响应速度。设短了能快速剔除死地址,让地址池的调度效率上一个台阶。
Q3:读取超时被误杀的请求怎么处理?
重试一次(换地址或原地址均可)。如果某类URL反复在读取超时边缘,说明页面确实大,为这类URL单独放宽读取超时。
Q4:怎么找到某站点的理想读取超时?
跑一轮采集统计读取耗时分布:P90耗时的1.5倍就是建议值。比拍脑袋准确得多。
Q5:使用代理IP有什么合规要求?
使用前须完成实名认证,只能用于数据采集、市场调研等合法场景;遵守目标网站的服务条款,不干扰目标网站正常运行。
timeout调优的核心就一句话:连接超时管快速失败,读取超时管页面适配,超时事件驱动地址调度。分层设置、按业务分档、用数据验证——超时从麻烦变成采集系统的神经信号。如需针对采集任务的参数诊断,可联系客户经理协助分析。