首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Python 爬虫网络层调优:超时、重试与连接池配置实践

Python 爬虫网络层调优:超时、重试与连接池配置实践

原创
作者头像
1024_officlal
发布2026-09-16 15:15:13
发布2026-09-16 15:15:13
1100
举报

做数据采集的朋友应该都经历过这种场景:代码逻辑没问题,请求头也伪装了,单次测试都能通过,但一上量就开始出现各种网络层的报错——ConnectionTimeoutReadTimeoutConnectionResetError,或者更隐蔽的:请求返回 200,但响应体是空的。

这些问题大多不是目标网站的反爬策略,而是网络层配置没做到位。本文从超时、重试、连接池三个角度,整理一套可落地的调优方案。

一、超时设置:连接超时和读取超时是两回事

很多人在 requests.get() 里只写一个 timeout=10,以为就设了 10 秒超时。实际上,requeststimeout 参数如果传单个数值,会同时作用于连接超时读取超时。但这两种超时的含义完全不同:

  • 连接超时:从发起 TCP 连接到建立连接的时间。这个值应该设短一点,3-5 秒足够。如果 5 秒还连不上,说明网络出口有问题,重试比干等更有效。
  • 读取超时:连接建立后,等待服务器返回第一个字节的时间。这个值需要设长一点,尤其是流式响应或大文件下载,模型“思考”阶段可能几十秒不输出数据。

正确写法是传一个元组:

代码语言:javascript
复制
import requests

# 连接超时 5 秒,读取超时 60 秒
response = requests.get(
    url,
    timeout=(5, 60)
)

如果是流式响应,读取超时要设得更长,建议 120 秒以上。

二、重试机制:别让一次抖动毁掉整个任务

网络抖动是常态,尤其是跨区域请求。没有重试机制的爬虫,稳定性完全靠运气。

requests 本身不提供自动重试,需要借助 urllib3Retry 类:

代码语言:javascript
复制
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

session = requests.Session()

retry = Retry(
    total=3,                    # 最多重试 3 次
    backoff_factor=1,           # 重试间隔:1s, 2s, 4s
    status_forcelist=[500, 502, 503, 504],  # 这些状态码触发重试
    allowed_methods=["GET", "POST"]
)

adapter = HTTPAdapter(max_retries=retry)
session.mount("http://", adapter)
session.mount("https://", adapter)

注意 backoff_factor 的指数退避效果:第一次重试等 1 秒,第二次等 2 秒,第三次等 4 秒。这样能避免短时间内密集重试把目标网站打挂。

三、连接池:并发上不去,问题往往在这里

requests 底层依赖 urllib3 的连接池,默认每个主机最多保持 10 个连接。如果你开了 50 个线程同时请求同一个域名,多出来的线程就在等空闲连接,等不到就卡死。

解决方案是根据并发数调整连接池大小:

代码语言:javascript
复制
adapter = HTTPAdapter(
    pool_connections=20,    # 连接池数量
    pool_maxsize=50,        # 每个池最大连接数
    max_retries=3
)
session.mount("http://", adapter)
session.mount("https://", adapter)

pool_maxsize 建议不小于并发线程数。如果并发是 50,就设 50 或更大。

四、出口 IP 的影响:为什么同样的代码在不同环境下表现不同

以上配置都调好后,如果仍然出现大面积超时或连接重置,问题可能出在网络出口上。

数据中心 IP(云服务器 IP)在访问部分海外站点时,容易被目标服务器的防护策略限速或拒绝。表现为:连接能建立,但读取阶段频繁超时,或者大文件下载中途被重置。这是因为目标站点对机房 IP 段有更严格的速率限制。

此时可以尝试更换网络出口为住宅 IP。住宅 IP 的 ASN 归属于当地运营商,在目标站点的访问策略中优先级更高,连接稳定性通常有明显改善。

以下是配置住宅 IP 出口的代码示例:

代码语言:javascript
复制
# ============================================
# 使用住宅IP出口(示例:1024Proxy)
# 官网:https://1024proxy.com/?kwd=hyj-txy
# ============================================

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

session = requests.Session()

# 配置住宅IP出口
proxy_url = "http://用户名:密码@gateway.example.com:端口"
session.proxies.update({
    "http": proxy_url,
    "https": proxy_url
})

# 同时配置重试和连接池
retry = Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
adapter = HTTPAdapter(pool_connections=20, pool_maxsize=50, max_retries=retry)
session.mount("http://", adapter)
session.mount("https://", adapter)

response = session.get(url, timeout=(5, 60))

注意代码中的 gateway.example.com 是占位符,实际使用时替换为服务商提供的网关地址即可。

五、几个容易忽略的细节

随机延迟比固定延迟更安全time.sleep(1) 不如 time.sleep(random.uniform(0.5, 2.0))。固定间隔的请求模式容易被识别为自动化流量。

异常捕获要区分类型ConnectionErrorTimeoutHTTPError 要分开处理。Timeout 可以重试,HTTPError 要看状态码决定是否重试。

先小规模测试:任何网络配置调整后,先用 100 个请求验证稳定性,再上量。不要一上来就跑几千条,出了问题不好定位。

六、小结

爬虫的稳定性,一半靠代码逻辑,一半靠网络层配置。超时设置、重试机制、连接池大小,每一项都直接影响任务的成功率。把这些细节调好,比盲目换 IP 更有效。

如果目标是海外站点,且本地出口是云服务器 IP,可以尝试将出口切换为住宅 IP 观察效果。具体的服务商选择需要根据实际业务场景测试,建议先用少量请求验证稳定性。


本文仅做技术交流,请遵守相关平台规则与法律法规。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、超时设置:连接超时和读取超时是两回事
  • 二、重试机制:别让一次抖动毁掉整个任务
  • 三、连接池:并发上不去,问题往往在这里
  • 四、出口 IP 的影响:为什么同样的代码在不同环境下表现不同
  • 五、几个容易忽略的细节
  • 六、小结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档