使用urllib2或任何其他http库进行读取超时
使用urllib2或任何其他http库进行读取超时
我有一段读取URL的代码,如下:\n
from urllib2 import Request, urlopen req = Request(url) for key, val in headers.items(): req.add_header(key, val) res = urlopen(req, timeout = timeout) # 这行代码会阻塞 content = res.read()
\ntimeout 参数可以用于 urlopen() 的调用。但是当代码执行到 res.read() 的时候,我想要读取响应数据,但超时设置并不适用于这里。因此,read() 方法可能会一直等待服务器传输数据而导致长时间卡住。我找到的唯一解决方案是使用信号来中断 read() 方法,但对我来说不太适用,因为我正在使用线程。\n还有其他选择吗?是否有适用于 Python 的处理读取超时的 HTTP 库?我已经看过 httplib2 和 requests,它们似乎都存在上述问题。我不想使用 socket 模块编写自己的非阻塞网络代码,因为我认为应该已经有一个库可以解决这个问题。\n更新: 下面的解决方案都不适用于我。你可以自己测试一下,在下载大文件时设置 socket 或 urlopen 的超时时间是没有效果的:\n
from urllib2 import urlopen url = 'http://iso.linuxquestions.org/download/388/7163/http/se.releases.ubuntu.com/ubuntu-12.04.3-desktop-i386.iso' c = urlopen(url) c.read()
\n至少在使用 Windows 和 Python 2.7.3 的情况下,超时设置完全被忽略了。
Read timeout using either urllib2 or any other http library(使用urllib2或任何其他http库时的读取超时)是一个常见的问题。当尝试从网络中读取数据时,可能会出现读取超时的情况,即无法在特定时间内读取到所需的数据。这可能是由于网络延迟,服务器响应速度慢或其他原因引起的。
解决这个问题的一个可能的方法是设置全局socket超时。可以通过以下代码实现:
import socket import urllib2 # 设置超时时间(单位:秒) socket.setdefaulttimeout(10) # 创建请求对象 req = urllib2.Request('http://www.voidspace.org.uk') # 发起请求并获取响应 response = urllib2.urlopen(req)
通过设置全局socket超时,可以在使用urllib2或其他http库发送请求时,将超时时间设置为默认值。然而,这种方法只适用于愿意全局修改socket模块超时时间的情况。如果在Celery任务中运行该请求,这样做可能会影响Celery工作代码本身的超时时间。
另一种解决方法是使用read()方法的超时参数。这可以确保在读取数据时也设置了超时时间。例如:
import urllib2 # 创建请求对象 req = urllib2.Request('http://www.voidspace.org.uk') # 发起请求并获取响应 response = urllib2.urlopen(req) # 设置读取超时时间(单位:秒) response.read(10, timeout=10)
这种方法可以更精确地控制读取操作的超时时间,避免长时间等待服务器响应。
需要注意的是,一些情况下,使用setdefaulttimeout()方法设置的超时时间可能不会对read()方法产生影响。例如,在Windows上使用Python 2.7版本时,setdefaulttimeout()方法对read()方法没有效果。在这种情况下,可以尝试其他方法或者查找其他解决方案。
总之,解决Read timeout using either urllib2 or any other http library的问题,可以通过设置全局socket超时或者使用read()方法的超时参数来控制读取操作的超时时间。这样可以确保在读取数据时,能够在特定的时间内获取到所需的数据,避免长时间等待或超时错误的发生。
在我的测试中,我发现在使用urlopen()
调用设置超时时间时,read()
调用也会受到影响:
import urllib2 as u c = u.urlopen('http://localhost/', timeout=5.0) s = c.read(1<<20) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.7/socket.py", line 380, in read data = self._sock.recv(left) File "/usr/lib/python2.7/httplib.py", line 561, in read s = self.fp.read(amt) File "/usr/lib/python2.7/httplib.py", line 1298, in read return s + self._file.read(amt - len(s)) File "/usr/lib/python2.7/socket.py", line 380, in read data = self._sock.recv(left) socket.timeout: timed out
也许这是较新版本的一个特性?我在一个12.04版本的Ubuntu上使用的是Python 2.7,初始状态下没有进行任何修改。
这可能会触发每个.recv()
调用的超时(可能会返回部分数据),但它不会限制总的读取超时时间(直到EOF)。
是的,这种澄清是有其价值的。
问题的原因是urllib2库在进行网络请求时,设置的超时时间只对每个.recv()调用生效,但无法限制总的读取超时时间。解决这个问题的方法是使用另外的HTTP库,例如requests库,该库提供了更灵活的超时设置。
以下是使用requests库解决这个问题的示例代码:
import requests try: response = requests.get('http://localhost/', timeout=5.0) s = response.content print(s) except requests.exceptions.Timeout: print("Request timed out") except requests.exceptions.RequestException as e: print(e)
使用requests库时,可以通过timeout参数设置总的读取超时时间。在上述代码中,timeout设置为5.0秒。如果请求超时,将会抛出requests.exceptions.Timeout异常。
通过使用requests库,我们可以更方便地控制超时时间,提高网络请求的稳定性和可靠性。
使用urllib2或任何其他HTTP库时发生的“读取超时”问题的原因是,这些库在底层使用的socket上设置了超时参数,该参数指定了接收操作的最长等待时间。如果在超时时间内没有接收到任何数据,那么会引发socket.timeout异常。简单来说,这是两个接收字节之间的超时。
解决这个问题的一个简单方法是使用threading.Timer来实现异步定时器。下面是一个使用threading.Timer的示例函数:
import httplib import socket import threading def download(host, path, timeout = 10): content = None http = httplib.HTTPConnection(host) http.request('GET', path) response = http.getresponse() timer = threading.Timer(timeout, http.sock.shutdown, [socket.SHUT_RD]) timer.start() try: content = response.read() except httplib.IncompleteRead: pass timer.cancel() http.close() return content
除了检查返回值是否为None之外,还可以在函数外部捕获httplib.IncompleteRead异常。但是,如果HTTP请求没有Content-Length头,后一种情况将无法工作。
此外,可以使用自定义异常来替代返回None,例如TimeoutError。
需要注意的是,异常是将错误从检测到错误的地方传递到知道如何处理错误的地方的机制。默认情况下,错误不会被忽略,这是更可靠的行为。
最后,还应该将超时参数传递给HTTPConnection来限制连接超时的时间。
解决“读取超时”问题的方法是使用异步定时器来设置超时,并使用异常来处理超时情况。