处理 urllib2.URLError 时获取 URL
这段内容主要是关于urllib2的,但也涉及到更广泛的自定义异常处理。我的问题是,如何通过抛出异常将额外的信息传递给另一个模块中的调用函数?我在想,我可能需要使用一个自定义的异常类来重新抛出这个异常,但具体的技术细节我还不太清楚。
为了不让示例代码变得复杂,我就不把我尝试过但失败的内容放进去,而是尽量保持代码的简洁。我的最终目标是让示例中的最后一行能够正常工作。
#mymod.py
import urllib2
def openurl():
req = urllib2.Request("http://duznotexist.com/")
response = urllib2.urlopen(req)
#main.py
import urllib2
import mymod
try:
mymod.openurl()
except urllib2.URLError as e:
#how do I do this?
print "Website (%s) could not be reached due to %s" % (e.url, e.reason)
2 个回答
0
我觉得重新抛出异常并不是解决这个问题的好办法。
正如 @Jonathan Vanasco 所说,
如果你打开 a.com 网站,它会自动跳转到 b.com,这时候 urlopen 会自动跟随这个跳转,因为出现了一个带重定向的 HTTP 错误。如果 b.com 导致了 URLError,那么上面的代码就会把 a.com 标记为不存在。
我的解决办法是重写 urllib2.HTTPRedirectHandler
的 redirect_request
方法。
import urllib2
class NewHTTPRedirectHandler(urllib2.HTTPRedirectHandler):
def redirect_request(self, req, fp, code, msg, headers, newurl):
m = req.get_method()
if (code in (301, 302, 303, 307) and m in ("GET", "HEAD")
or code in (301, 302, 303) and m == "POST"):
newurl = newurl.replace(' ', '%20')
newheaders = dict((k,v) for k,v in req.headers.items()
if k.lower() not in ("content-length", "content-type")
)
# reuse the req object
# mind that req will be changed if redirection happends
req.__init__(newurl,
headers=newheaders,
origin_req_host=req.get_origin_req_host(),
unverifiable=True)
return req
else:
raise HTTPError(req.get_full_url(), code, msg, headers, fp)
opener = urllib2.build_opener(NewHTTPRedirectHandler)
urllib2.install_opener(opener)
# mind that req will be changed if redirection happends
#req = urllib2.Request('http://127.0.0.1:5000')
req = urllib2.Request('http://www.google.com/')
try:
response = urllib2.urlopen(req)
except urllib2.URLError as e:
print 'error'
print req.get_full_url()
else:
print 'normal'
print response.geturl()
我们来试着把网址重定向到一个未知的网址:
import os
from flask import Flask,redirect
app = Flask(__name__)
@app.route('/')
def hello():
# return 'hello world'
return redirect("http://a.com", code=302)
if __name__ == '__main__':
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port)
结果是:
error
http://a.com/
normal
http://www.google.com/
8
你可以在异常中添加一些信息,然后再把这个异常抛出来。
#mymod.py
import urllib2
def openurl():
req = urllib2.Request("http://duznotexist.com/")
try:
response = urllib2.urlopen(req)
except urllib2.URLError as e:
# add URL and reason to the exception object
e.url = "http://duznotexist.com/"
e.reason = "URL does not exist"
raise e # re-raise the exception, so the calling function can catch it
#main.py
import urllib2
import mymod
try:
mymod.openurl()
except urllib2.URLError as e:
print "Website (%s) could not be reached due to %s" % (e.url, e.reason)