Python 处理urllib2.URLError时获取URL

Python 处理urllib2.URLError时获取URL,python,exception-handling,urllib2,Python,Exception Handling,Urllib2,这特别适用于urllib2,但更普遍的是自定义异常处理。如何通过引发的异常将附加信息传递给另一个模块中的调用函数?我假设我将使用自定义异常类重新引发,但我不确定技术细节 与其用我尝试过但失败的东西来污染示例代码,不如简单地将其呈现为一张白板。我的最终目标是让示例中的最后一行工作 #mymod.py import urllib2 def openurl(): req = urllib2.Request("http://duznotexist.com/") response = u

这特别适用于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)

您可以向添加信息,然后重新引发异常

#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)

我不认为重新提出例外是解决这个问题的适当方法

正如@Jonathan Vanasco所说

如果您正在打开a.com,并且它301重定向到b.com,urlopen将自动跟随它,因为引发了带有重定向的HTTPError。如果b.com导致URL错误,则上述代码会将a.com标记为不存在

我的解决方案是覆盖
urlib2.HTTPRedirectHandler的
redirect\u请求

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()
让我们尝试将url重定向到未知url:

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/

+是的,这就是我要找的。我觉得这很简单,但我只是没有通过谷歌或试错来实现。urlib2.urlopen()将遵循重定向-因此
e.url\u original
更合适。我还没有弄清楚如何获取触发URLError的
url\u actual
。我不想在这里吹毛求疵。如果您正在打开a.com,并且它301重定向到b.com,urlopen将自动跟随它,因为引发了带有重定向的HTTPError。如果b.com导致url错误,上面的代码会将a.com标记为不存在-当它确实存在并且工作正常时,它只会指向b.com上的错误url。
e.reason=“url不存在”
将提供
AttributeError:can't set attribute