2009-08-20 11 views
25

Contexte: J'utilise urllib.urlretrieve, par opposition à toute autre fonction dans les urllib* modules, en raison du soutien de la fonction crochet (voir ci-dessous reporthook) .. qui est utilisé pour afficher un texte barre de progression. C'est Python> = 2.6.Comment attraper 404 erreur dans urllib.urlretrieve

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

Cependant, urlretrieve est si bête qu'il ne laisse aucun moyen de détecter l'état de la requête HTTP (par exemple: est-il 404 ou 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 
'' 
>>> 

Quelle est la meilleure façon connue de télécharger un fichier HTTP distant avec le support en forme de crochet (pour afficher la barre de progression) et une gestion des erreurs HTTP décent?

+0

Ne pas fournir un statut HTTP sur votre demande devrait probablement être considéré comme un bug dans le fichier stdlib (mais vérifiez la bibliothèque bien meilleure, les requêtes, ci-dessous) –

Répondre

27

Check out de code complet de urllib.urlretrieve:

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

En d'autres termes, vous pouvez utiliser urllib.FancyURLopener (il fait partie de l'API urllib public). Vous pouvez remplacer http_error_default pour détecter 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

Je ne veux pas spécifier de gestionnaires; Est-ce qu'il lance des exceptions comme urllib2.urlopen? –

+4

Il est très facile de le faire lancer. FancyURLopener sous-classes URLopener qui lance, donc vous pouvez essayer d'appeler l'implémentation de la classe de base: def http_error_default (...): URLopener.http_error_default (...) – orip

+0

Ceci est une très bonne solution, je l'ai utilisé moi-même tout à l'heure. –

14

Vous devez utiliser:

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) 

Editer: La raison d'être ici est que sauf si vous attendez la st mangé, c'est une exception pour que cela se produise, et vous n'y avez probablement même pas pensé - ainsi, au lieu de laisser votre code continuer à fonctionner en cas d'échec, le comportement par défaut est - assez sensiblement - d'inhiber son exécution.

+2

support de type crochet? –

+1

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