2011-06-28 19 views
7

Esto se refiere específicamente a urllib2, pero el manejo de excepciones personalizadas de manera más general. ¿Cómo paso información adicional a una función de llamada en otro módulo a través de una excepción planteada? Supongo que volvería a subir con una clase de excepción personalizada, pero no estoy seguro de los detalles técnicos.Obtenga la URL al manejar urllib2.URLEror

En lugar de contaminar el código de muestra con lo que he intentado y fallé, simplemente lo presentaré como una pizarra en blanco. Mi objetivo final es que la última línea de la muestra funcione.

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

Respuesta

8

Puede agregar información y volver a generar la excepción.

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

+1 Sí, eso es lo que estaba buscando. Pensé que era simple, pero simplemente no estaba llegando a través de google o prueba y error. – mwolfe02

+1

urlib2.urlopen() seguirá las redirecciones, por lo que 'e.url_original' sería más apropiado. no he podido averiguar cómo obtener el 'url_actual' que desencadenó el URLError. no estoy tratando de nitpick aquí. si está abriendo a.com, y 301 redirecciona a b.com, urlopen automáticamente lo seguirá porque se generó un HTTPError con una redirección. si b.com causa URLError, el código anterior marca a.com como no existente; cuando funciona y funciona perfectamente, solo apunta a una URL incorrecta en b.com. –

+0

'e.reason =" URL no existe "' proporcionará 'AttributeError: no se puede establecer el atributo' – histrio

0

No creo que volver a plantear la excepción sea una forma adecuada de resolver este problema.

Como dijo @ Jonathan Vanasco,

if you're opening a.com , and it 301 redirects to b.com , urlopen will automatically follow that because an HTTPError with a redirect was raised. if b.com causes the URLError , the code above marks a.com as not existing

Mi solución es sobrescribir redirect_request de urllib2.HTTPRedirectHandler

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

vamos a tratar de redirigir la dirección URL a una URL desconocida:

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) 

Y el resultado es:

error 
http://a.com/ 

normal 
http://www.google.com/