2009-03-20 12 views
51

Tengo el siguiente código para hacer una devolución de datos a una URL remota:¿Qué errores/excepciones debo manejar con urllib2.Request/urlopen?

request = urllib2.Request('http://www.example.com', postBackData, { 'User-Agent' : 'My User Agent' }) 

try: 
    response = urllib2.urlopen(request) 
except urllib2.HTTPError, e: 
    checksLogger.error('HTTPError = ' + str(e.code)) 
except urllib2.URLError, e: 
    checksLogger.error('URLError = ' + str(e.reason)) 
except httplib.HTTPException, e: 
    checksLogger.error('HTTPException') 

El postBackData se crea utilizando un diccionario codificado utilizando urllib.urlencode. checksLogger es un registrador que usa logging.

Tuve un problema donde este código se ejecuta cuando el servidor remoto está inactivo y el código sale (esto está en los servidores del cliente, así que no sé cuál es el volcado/error de la pila de salida en este momento). Estoy asumiendo que esto se debe a que hay una excepción y/o error que no se está manejando. Entonces, ¿hay alguna otra excepción que pueda desencadenarse que no estoy manejando arriba?

Respuesta

50

Añadir manejador de excepción genérica:

request = urllib2.Request('http://www.example.com', postBackData, { 'User-Agent' : 'My User Agent' }) 

try: 
    response = urllib2.urlopen(request) 
except urllib2.HTTPError, e: 
    checksLogger.error('HTTPError = ' + str(e.code)) 
except urllib2.URLError, e: 
    checksLogger.error('URLError = ' + str(e.reason)) 
except httplib.HTTPException, e: 
    checksLogger.error('HTTPException') 
except Exception: 
    import traceback 
    checksLogger.error('generic exception: ' + traceback.format_exc()) 
+0

es 'checksLogger.error' una función definida por el usuario en su ejemplo? – codingknob

+1

@ algotr8der: sí, es solo copiar y pegar de la sesión de la pregunta – vartec

+0

bien genial. Gracias. – codingknob

1

Puede capturar todas las excepciones y registrar lo que de quedar atrapados:

import sys 
import traceback 
def formatExceptionInfo(maxTBlevel=5): 
    cla, exc, trbk = sys.exc_info() 
    excName = cla.__name__ 
    try: 
     excArgs = exc.__dict__["args"] 
    except KeyError: 
     excArgs = "<no args>" 
    excTb = traceback.format_tb(trbk, maxTBlevel) 
    return (excName, excArgs, excTb) 
try: 
    x = x + 1 
except: 
    print formatExceptionInfo() 

(Código de http://www.linuxjournal.com/article/5821)

Lea también documentation on sys.exc_info.

+0

Es mejor usar "excepto Excepción:" para que no detecte los errores que causarán problemas en su manejador excepto. –

+0

Es mejor no detectar excepciones en absoluto si solo las está registrando. Consulte mi respuesta. –

+0

@ S.Lott: gracias, es un truco con el que no estaba familiarizado –

15

Desde la entrada docs pageurlopen, parece que solo tiene que atrapar URLError. Si realmente desea cubrir sus apuestas contra los problemas dentro del código urllib, también puede detectar Exception como un retroceso. Haga no solo except:, ya que eso capturará SystemExit y KeyboardInterrupt también.

Editar: Lo que quiero decir es que está captando los errores que se supone que arroja. Si está lanzando algo más, es probable que se deba a que el código urllib no detecta algo que debería haber capturado y envuelto en un URLError. Incluso el stdlib tiende a perder cosas simples como AttributeError. Capturar Exception como un retroceso (y registrar lo capturado) lo ayudará a descubrir lo que está sucediendo, sin atrapar SystemExit y KeyboardInterrupt.

+1

+1 para el enlace a los documentos, y los consejos claros sobre excepciones –

+3

+1 para informarme sobre la diferencia entre except: y excepto Exception (al menos uno de ellos) . – hyperboreean

+0

¿Excepto urllib2.URLError, e: not already catch URLError? – DavidM

13
$ grep "raise" /usr/lib64/python/urllib2.py 
IOError); for HTTP errors, raises an HTTPError, which can also be 
     raise AttributeError, attr 
       raise ValueError, "unknown url type: %s" % self.__original 
     # XXX raise an exception if no one else should try to handle 
     raise HTTPError(req.get_full_url(), code, msg, hdrs, fp) 
     perform the redirect. Otherwise, raise HTTPError if no-one 
      raise HTTPError(req.get_full_url(), code, msg, headers, fp) 
       raise HTTPError(req.get_full_url(), code, 
      raise HTTPError(req.get_full_url(), 401, "digest auth failed", 
       raise ValueError("AbstractDigestAuthHandler doesn't know " 
      raise URLError('no host given') 
      raise URLError('no host given') 
      raise URLError(err) 
     raise URLError('unknown url type: %s' % type) 
     raise URLError('file not on local host') 
      raise IOError, ('ftp error', 'no host given') 
      raise URLError(msg) 
      raise IOError, ('ftp error', msg), sys.exc_info()[2] 
      raise GopherError('no host given') 

También existe la posibilidad de excepciones en dependencias urllib2, o de excepciones causadas por errores genuinos.

Es mejor que registre todas las excepciones no detectadas en un archivo a través de un sys.excepthook personalizado. La regla principal aquí es nunca detectar excepciones que no está planeando corregir, y el registro no es una corrección. Así que no los atrape solo para registrarlos.

0

capto:

httplib.HTTPException
urllib2.HTTPError
urllib2.URLError

Creo que esto cubre todo, incluyendo errores de socket.

+2

'urllib2.HTTPError' es una subclase de' urllib2.URLError', por lo que captura el el segundo es suficiente – pictuga

+1

ninguno de estos captura socket.error –

Cuestiones relacionadas