2009-08-20 10 views
25

Antecedentes: Estoy usando urllib.urlretrieve, a diferencia de cualquier otra función en los módulos urllib*, debido a la compatibilidad con la función de enlace (véase reporthook a continuación) .. que se utiliza para mostrar un texto barra de progreso. Esto es Python> = 2.6.Cómo atrapar el error 404 en urllib.urlretrieve

>>> urllib.urlretrieve(url[, filename[, reporthook[, data]]]) 

Sin embargo, urlretrieve es tan tonto que no deja manera de detectar el estado de la solicitud HTTP (por ejemplo: ¿era 404 o 200?).

>>> fn, h = urllib.urlretrieve('http://google.com/foo/bar') 
>>> h.items() 
[('date', 'Thu, 20 Aug 2009 20:07:40 GMT'), 
('expires', '-1'), 
('content-type', 'text/html; charset=ISO-8859-1'), 
('server', 'gws'), 
('cache-control', 'private, max-age=0')] 
>>> h.status 
'' 
>>> 

¿Cuál es la mejor manera conocida para descargar un archivo remoto HTTP con el apoyo en forma de gancho (para mostrar la barra de progreso) y un control de errores HTTP decente?

+0

No proporcionar un estado HTTP en su solicitud probablemente se deba considerar un error en el stdlib (pero consulte la biblioteca, las solicitudes, mucho mejor a continuación) –

Respuesta

27

Salida urllib.urlretrieve 's código completo:

def urlretrieve(url, filename=None, reporthook=None, data=None): 
    global _urlopener 
    if not _urlopener: 
    _urlopener = FancyURLopener() 
    return _urlopener.retrieve(url, filename, reporthook, data) 

En otras palabras, se puede utilizar urllib.FancyURLopener (es parte de la API urllib público). Puede anular http_error_default para detectar 404s:

class MyURLopener(urllib.FancyURLopener): 
    def http_error_default(self, url, fp, errcode, errmsg, headers): 
    # handle errors the way you'd like to 

fn, h = MyURLopener().retrieve(url, reporthook=my_report_hook) 
+0

No quiero especificar manipuladores; ¿Lanza excepciones como urllib2.urlopen? –

+4

Es muy fácil hacerlo tirar. FancyURLopener subclases URLopener que no lanza, por lo que puedes intentar llamar a la implementación de la clase base: def http_error_default (...): URLopener.http_error_default (...) – orip

+0

Esta es una muy buena solución, yo mismo la utilicé hace un momento. –

14

Deberá utilizar:

import urllib2 

try: 
    resp = urllib2.urlopen("http://www.google.com/this-gives-a-404/") 
except urllib2.URLError, e: 
    if not hasattr(e, "code"): 
     raise 
    resp = e 

print "Gave", resp.code, resp.msg 
print "=" * 80 
print resp.read(80) 

Edit: La razón de ser es que a menos que espere el excepcional st comió, es una excepción que ocurra, y probablemente ni siquiera lo pensó, así que en lugar de dejar que su código continúe ejecutándose mientras no fue exitoso, el comportamiento predeterminado es, con bastante sensatez, inhibir su ejecución.

+2

¿Soporte con forma de gancho? –

+1

Sridhar, ver http://stackoverflow.com/a/9740603/819417 –