我正在使用请求库从某个地方获取大量网页。他是相关的代码:
response = requests.Session()
retries = Retry(total=5, backoff_factor=.1)
response.mount('http://', HTTPAdapter(max_retries=retries))
response = response.get(url)
过了一会儿,它只是在获取页面时挂起/冻结(从不在同一个网页上)。这是我打断它时的追溯:
File "/Users/Student/Hockey/Scrape/html_pbp.py", line 21, in get_pbp
response = r.read().decode('utf-8')
File "/anaconda/lib/python3.6/http/client.py", line 456, in read
return self._readall_chunked()
File "/anaconda/lib/python3.6/http/client.py", line 566, in _readall_chunked
value.append(self._safe_read(chunk_left))
File "/anaconda/lib/python3.6/http/client.py", line 612, in _safe_read
chunk = self.fp.read(min(amt, MAXAMOUNT))
File "/anaconda/lib/python3.6/socket.py", line 586, in readinto
return self._sock.recv_into(b)
KeyboardInterrupt
有人知道是什么原因引起的吗?或者(更重要的是)是否有人知道如果需要超过一定的时间才能阻止它,以便我可以再试一次?
答案 0 :(得分:10)
似乎设置(阅读)timeout可能对您有帮助。
有些事情:
response = response.get(url, timeout=5)
(这会将连接和读取超时都设置为5秒。)
遗憾的是,在requests
中,默认设置 connect 和 read 超时,即使docs说出来了很高兴设置它:
如果服务器未及时响应,则对外部服务器的大多数请求应附加超时。默认情况下,除非明确设置超时值,否则请求不会超时。如果没有超时,您的代码可能会挂起几分钟或更长时间。
为了完整起见,连接超时是等待客户端与远程计算机建立连接的秒数requests
以及读取超时> strong>是客户端在从服务器发送的字节之间等待的秒数。
答案 1 :(得分:1)
修补记录的“发送”功能将针对所有请求解决此问题-即使在许多依赖的库和sdk中也是如此。修补库时,请务必修补受支持/已记录的功能,否则您可能会无声无息地失去修补效果。
import requests
DEFAULT_TIMEOUT = 180
old_send = requests.Session.send
def new_send(*args, **kwargs):
if kwargs.get("timeout", None) is None:
kwargs["timeout"] = DEFAULT_TIMEOUT
return old_send(*args, **kwargs)
requests.Session.send = new_send
没有任何超时的影响非常严重,并且使用默认超时几乎不会破坏任何东西-因为TCP本身也有超时。
在Windows上,默认的TCP超时为240秒,TCP RFC建议RTO * retry至少为100秒。在该范围内的某个位置是安全的默认值。
答案 2 :(得分:0)
要全局设置超时,而不是在每个请求中都指定:
from requests.adapters import TimeoutSauce
REQUESTS_TIMEOUT_SECONDS = float(os.getenv("REQUESTS_TIMEOUT_SECONDS", 5))
class CustomTimeout(TimeoutSauce):
def __init__(self, *args, **kwargs):
if kwargs["connect"] is None:
kwargs["connect"] = REQUESTS_TIMEOUT_SECONDS
if kwargs["read"] is None:
kwargs["read"] = REQUESTS_TIMEOUT_SECONDS
super().__init__(*args, **kwargs)
# Set it globally, instead of specifying ``timeout=..`` kwarg on each call.
requests.adapters.TimeoutSauce = CustomTimeout
sess = requests.Session()
sess.get(...)
sess.post(...)