如何在urllib2中超时后重试加载页面?
我想让Python在遇到超时错误时重新加载页面。有没有办法让我设置它重试特定的次数,可能还要在特定的时间间隔后再重试?
任何帮助都非常感谢。
谢谢。
3 个回答
可以看看这个requests
库。如果你只想等一段指定的时间(不是等整个下载完成,而是等服务器给你回应),只需要在标准的URL请求中加上timeout
参数,单位是秒:
r = requests.get(url, timeout=10)
如果超过了timeout
设定的时间,就会抛出一个requests.exceptions.Timeout
异常,你可以根据自己的需要来处理这个异常。比如,你可以把请求放在一个try/except块里,如果抛出异常,就捕获它,并在指定的次数内重新尝试连接,直到彻底失败。
你可能还想了解一下requests.adapters.HTTPAdapter
,它有一个max_retries
参数。这个通常是在Requests的Session
中使用,根据文档,它提供了一个通用的接口,让Requests会话能够通过实现传输适配器接口来联系HTTP和HTTPS网址。
虽然我也是刚接触Python,但我觉得像这样的简单解决方案也许能解决问题。
首先可以把一些东西看作是None,也就是空值,这里的“东西”指的是页面源代码(page_source)。另外,我只考虑了URLError这个错误类型,你可以根据需要添加更多的错误处理。
import urllib2
import time
stuff=None
max_attempts=4
r=0
while stuff is None and r<max_attempts:
try:
response = urllib2.urlopen('http://www.google.com/ncr', timeout=10)
stuff = response.read()
except urllib2.URLError:
r=r+1
print "Re-trying, attempt -- ",r
time.sleep(5)
pass
print stuff
希望这能帮到你。
祝好,
Md. Mohsin
urllib2
里没有现成的功能来处理这个问题,但你可以自己写一个。
比较棘手的是,正如urlopen
的文档所说,无论发生什么错误,你得到的都是一个 URLError
。那么,怎么知道是超时了,还是其他问题呢?
如果你查一下URLError
,会发现它有一个 reason
,对于远程网址来说,这个 reason
是 socket.error
。再查一下socket.error
,你会看到它是 IOError
或 OSError
的子类(具体取决于你的 Python 版本)。再查一下OSError
,你会发现它有一个 errno
,用来表示底层的错误。
那么,超时的 errno
值是什么呢?我敢打赌是 EINPROGRESS
,但我们来确认一下:
>>> urllib.urlopen('http://127.0.0.1', timeout=0)
urllib2.URLError: <urlopen error [Errno 36] Operation now in progress>
>>> errno.errorcode[36]
'EINPROGRESS'
(你可以直接用数字 36,但这个数字在不同平台上不一定相同;使用 errno.EINPROGRESS
会更通用。)
所以:
import errno
import urllib2
def retrying_urlopen(retries, *args, **kwargs):
for i in range(retries):
try:
return urllib2.urlopen(*args, **kwargs)
except URLError as e:
if e.reason.errno == errno.EINPROGRESS:
continue
raise
如果你觉得这个过程很麻烦,应该更简单一些……我想大家都同意这一点。异常处理已经经历了两次大幅改进,接下来还会有一次大的改进,以及一些小的变化。但如果你还在用 2.7 版本,就享受不到这些改进的好处。
如果不能升级到 Python 3.4,也许可以考虑使用像 requests
或 urllib3
这样的第三方模块。这两个库都有专门处理 Timeout
的异常类型,而不是让你去处理一个通用的 URLError
的细节。