Python中关于requests库timeout参数的疑问与使用详解

仔细看了下 requests 的官方文档,其中特别注明

“timeout 仅对连接过程有效,与响应体的下载无关。 timeout 并不是整个下载响应的时间限制,而是如果服务器在 timeout 秒内没有应答,将会引发一个异常(更精确地说,是在 timeout 秒内没有从基础套接字上接收到任何字节的数据时)”

现在遇到一个网站,响应时间非常快,但是"响应体的下载"非常慢,估计是防封策略故意设置的,这样我该如何应对呢?求老司机.
Python中关于requests库timeout参数的疑问与使用详解

11 回复

比如你抓取某台国内机器的资源,因为是在国内,所以建立连接很快,但它带宽只有 1M ,所以下载响应体很慢。


帖子回复:

关于 requests 库的 timeout 参数,核心就两点:连接超时读取超时。这俩是分开控制的,但用一个参数就能搞定。

1. 基本用法

import requests

# 设置总超时(连接+读取)为5秒
response = requests.get('https://api.example.com', timeout=5)

# 分别设置连接超时2秒,读取超时10秒
response = requests.get('https://api.example.com', timeout=(2, 10))

2. 关键细节

  • 连接超时:从发请求到建立连接的时间,包括DNS解析、TCP握手、SSL握手
  • 读取超时:连接建立后,等待服务器返回第一个字节的时间
  • 超时异常:连接超时抛 ConnectTimeout,读取超时抛 ReadTimeout
  • 默认行为:不设置timeout时,requests会一直等待(生产环境千万别这样!)

3. 实际场景示例

import requests
from requests.exceptions import Timeout, ConnectionError

try:
    # 对慢速API:快速失败连接,但允许较长的读取时间
    response = requests.get('https://slow-api.com/data', timeout=(3, 30))
    print("请求成功")
    
except Timeout as e:
    if isinstance(e, requests.exceptions.ConnectTimeout):
        print("连接超时 - 服务器太慢或网络有问题")
    elif isinstance(e, requests.exceptions.ReadTimeout):
        print("读取超时 - 服务器处理请求太慢")
        
except ConnectionError:
    print("连接错误 - 检查网络或URL")

4. 最佳实践

  • 永远设置timeout:生产代码必须设置,防止线程/进程被卡死
  • 区分内外网:内网服务可以用(2, 5),外网API建议(3, 10)
  • 文件上传下载:读取超时要设长点,比如 timeout=(5, 60)
  • Session复用:给Session对象设置默认timeout
session = requests.Session()
session.request = functools.partial(session.request, timeout=(3, 10))

总结:timeout就是你的安全绳,不系就别爬高。

request 支持 stream 的方式,自己分片读,然后判断是否超时

现在就是响应体下载很慢,想设置一个超时,应该怎么做呢?

如果我想设置一个针对响应体的超时怎么办呢?



http://docs.python-requests.org/en/master/user/advanced/#streaming-requests

started_time = time.time()
timeout = 60

r = requests.get(‘http://httpbin.org/stream/20’, stream=True)

if r.encoding is None:
r.encoding = 'utf-8’

for line in r.iter_lines(decode_unicode=True):
if time.time() - started_time > 60:
print “timeout”
break
if line:
print json.loads(line)

感谢~~~,难为了我一下午的问题貌似有着落了,ORZ

timeout 可以设置 tuple 的, http://docs.python-requests.org/en/master/api/

看文档啊,少年。

这个路子好野。 60 是拍脑袋出来的? 万一 10s 服务端就把连接关了呢。

这个只是举个例子可以这样玩

要是服务器端关闭了,这个迭代器应该是会抛出异常的

但实际上它并不会抛出异常,至少我断网了 10 分钟还是正常的

回到顶部