处理 urllib2.URLError 时获取 URL

8 投票
2 回答
8384 浏览
提问于 2025-04-16 20:27

这段内容主要是关于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.HTTPRedirectHandlerredirect_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)

撰写回答