首先,我的问题与this one非常相似。我希望urllib.urlopen()超时以生成我可以处理的异常。
这不属于URLError吗?
try:
response = urllib.request.urlopen(url, timeout=10).read().decode('utf-8')
except (HTTPError, URLError) as error:
logging.error(
'Data of %s not retrieved because %s\nURL: %s', name, error, url)
else:
logging.info('Access successful.')
错误消息:
resp = urllib.request.urlopen(req,timeout = 10).read()。decode('utf-8')
文件“/usr/lib/python3.2/urllib/request.py”,第138行,在urlopen中 return opener.open(url,data,timeout)
文件“/usr/lib/python3.2/urllib/request.py”,第369行,处于打开状态
response = self._open(req,data)
文件“/usr/lib/python3.2/urllib/request.py”,第387行,在_open中 '_open',req)
文件“/usr/lib/python3.2/urllib/request.py”,第347行,在_call_chain中 result = func(* args)
在http_open中输入文件“/usr/lib/python3.2/urllib/request.py”,第1156行 return self.do_open(http.client.HTTPConnection,req)
文件“/usr/lib/python3.2/urllib/request.py”,第1141行,在do_open中 r = h.getresponse()
文件“/usr/lib/python3.2/http/client.py”,第1046行,在getresponse中 response.begin()
文件“/usr/lib/python3.2/http/client.py”,第346行,开头
版本,状态,原因= self._read_status()
文件“/usr/lib/python3.2/http/client.py”,第308行,在_read_status中 line = str(self.fp.readline(_MAXLINE + 1),“iso-8859-1”)
文件“/usr/lib/python3.2/socket.py”,第276行,在readinto中 return self._sock.recv_into(b)
socket.timeout:超时
当他们将urllib
和urllib2
模块重组为urllib
时,Python 3发生了重大变化。是否有可能导致这种情况发生变化?
答案 0 :(得分:27)
例外是socket的超时,所以
from socket import timeout
try:
response = urllib.request.urlopen(url, timeout=10).read().decode('utf-8')
except (HTTPError, URLError) as error:
logging.error('Data of %s not retrieved because %s\nURL: %s', name, error, url)
except timeout:
logging.error('socket timed out - URL %s', url)
else:
logging.info('Access successful.')
应该抓住新的例外。
答案 1 :(得分:5)
上一个答案无法正确拦截超时错误。超时错误会引发为URLError
,因此,如果要专门捕获它们,则需要编写:
from urllib.error import HTTPError, URLError
import socket
try:
response = urllib.request.urlopen(url, timeout=10).read().decode('utf-8')
except HTTPError as error:
logging.error('Data not retrieved because %s\nURL: %s', error, url)
except URLError as error:
if isinstance(error.reason, socket.timeout):
logging.error('socket timed out - URL %s', url)
else:
logging.error('some other error happened)
else:
logging.info('Access successful.')
请注意,ValueError
可以独立引发,即网址无效。像HTTPError
一样,它与超时无关。
答案 2 :(得分:0)
什么是“超时”?总的来说,我认为这意味着“服务器没有及时响应的情况,通常是因为高负载,值得再试一次。”
HTTP 状态 504“网关超时”将是此定义下的超时。它通过 HTTPError 传递。
HTTP 状态 429“请求过多”也属于该定义下的超时。它也是通过 HTTPError 传递的。
否则,超时是什么意思?我们是否在通过 DNS 解析器解析域名时包含超时?尝试发送数据时超时?等待数据返回时超时?
我不知道如何审核 urllib 的源代码,以确保我可能会考虑超时的所有可能方式都以我能理解的方式提出。在没有检查异常的语言中,我不知道如何。我有一种预感,连接到 dns 错误可能会作为 socket.timeout 返回,而连接到远程服务器错误可能会作为 URLError(socket.timeout) 返回?这只是一种猜测,可以解释早期的观察结果。
所以我回到了一些真正防御性的编码。 (1) 我正在处理一些指示超时的 HTTP 状态代码。 (2) 有报告说有些超时是通过 socket.timeout 异常产生的,有些是通过 URLError(socket.timeout) 异常产生的,所以我同时抓住了两者。 (3) 为了以防万一,我也抛出了 HTTPError(socket.timeout)。
while True:
reason : Optional[str] = None
try:
with urllib.request.urlopen(url) as response:
content = response.read()
with open(cache,"wb") as file:
file.write(content)
return content
except urllib.error.HTTPError as e:
if e.code == 429 or e.code == 504: # 429=too many requests, 504=gateway timeout
reason = f'{e.code} {str(e.reason)}'
elif isinstance(e.reason, socket.timeout):
reason = f'HTTPError socket.timeout {e.reason} - {e}'
else:
raise
except urllib.error.URLError as e:
if isinstance(e.reason, socket.timeout):
reason = f'URLError socket.timeout {e.reason} - {e}'
else:
raise
except socket.timeout as e:
reason = f'socket.timeout {e}'
except:
raise
netloc = urllib.parse.urlsplit(url).netloc # e.g. nominatim.openstreetmap.org
print(f'*** {netloc} {reason}; will retry', file=sys.stderr)
time.sleep(5)