2009-06-12 10 views
48

urllib.urlretrieve retourne en mode silencieux même si le fichier n'existe pas sur le serveur http distant, il enregistre simplement une page HTML dans le fichier nommé. Par exemple:Comment savoir si urllib.urlretrieve réussit?

urllib.urlretrieve('http://google.com/abc.jpg', 'abc.jpg') 

retourne juste en silence, même si abc.jpg n'existe pas sur le serveur google.com, généré abc.jpg n'est pas un fichier jpg valide, il est en fait une page html. Je suppose que les en-têtes retournés (une instance de httplib.HTTPMessage) peuvent être utilisés pour dire réellement si les réussites de récupération ou non, mais je ne trouve pas de doc pour httplib.HTTPMessage.

Quelqu'un peut-il fournir des informations sur ce problème?

Répondre

22

Pensez à utiliser urllib2 si c'est possible dans votre cas. Il est plus avancé et facile à utiliser que urllib.

Vous pouvez détecter des erreurs HTTP facilement:

>>> import urllib2 
>>> resp = urllib2.urlopen("http://google.com/abc.jpg") 
Traceback (most recent call last): 
<<MANY LINES SKIPPED>> 
urllib2.HTTPError: HTTP Error 404: Not Found 

resp est en fait l'objet HTTPResponse que vous pouvez faire beaucoup de choses utiles avec:

>>> resp = urllib2.urlopen("http://google.com/") 
>>> resp.code 
200 
>>> resp.headers["content-type"] 
'text/html; charset=windows-1251' 
>>> resp.read() 
"<<ACTUAL HTML>>" 
+6

Est-ce que urllib2 peut fournir le comportement de cache de urlretrieve? Ou devrions-nous le réimplémenter? – Kiv

+0

Voir cet effroyable recipie d'ActiveState: http://code.activestate.com/recipes/491261/ Nous l'utilisons dans notre projet actuel, fonctionne parfaitement –

+1

urlopen ne fournit pas une fonction de crochet (pour montrer la barre de progression pour exemple) comme urlretrieve. –

2

Selon la documentation est est undocumented

pour accéder au message il semble que vous faites quelque chose comme:

a, b=urllib.urlretrieve('http://google.com/abc.jpg', r'c:\abc.jpg') 

b est l'instance de message

Depuis que je l'ai appris que Python, il est toujours utile d'utiliser la capacité de Python à être introspectif lorsque je tape

dir(b) 

Je vois beaucoup de méthodes ou fonctions pour jouer avec

Et puis j'ai commencé à faire des choses avec b

par exemple

b.items() 

Listes beaucoup de choses intéressantes, je pense que jouer avec ces choses vous permettront d'obtenir l'attribut que vous voulez manipuler.

Désolé, c'est une réponse tellement débutant mais j'essaie de maîtriser comment utiliser les capacités d'introspection pour améliorer mon apprentissage et vos questions surgissent.

Eh bien j'ai essayé quelque chose d'intéressant lié à ce, je me demandais si je pouvais obtenir automatiquement la sortie de chacune des choses qui a montré dans le répertoire qui n'a pas besoin de paramètres j'ai donc écrit:

needparam=[] 
for each in dir(b): 
    x='b.'+each+'()' 
    try: 
     eval(x) 
     print x 
    except: 
     needparam.append(x) 
+0

Aucun statut pour moi, et votre code ne fonctionne qu'une seule fois. Essayez 'pour k dans b: print"% s:% r "% (k, b [k])' –

1

J'ai fini avec ma propre retrieve mise en œuvre , avec l'aide de pycurl il prend en charge plus de protocoles que urllib/urllib2, espérons qu'il peut aider les autres.

import tempfile 
import pycurl 
import os 

def get_filename_parts_from_url(url): 
    fullname = url.split('/')[-1].split('#')[0].split('?')[0] 
    t = list(os.path.splitext(fullname)) 
    if t[1]: 
     t[1] = t[1][1:] 
    return t 

def retrieve(url, filename=None): 
    if not filename: 
     garbage, suffix = get_filename_parts_from_url(url) 
     f = tempfile.NamedTemporaryFile(suffix = '.' + suffix, delete=False) 
     filename = f.name 
    else: 
     f = open(filename, 'wb') 
    c = pycurl.Curl() 
    c.setopt(pycurl.URL, str(url)) 
    c.setopt(pycurl.WRITEFUNCTION, f.write) 
    try: 
     c.perform() 
    except: 
     filename = None 
    finally: 
     c.close() 
     f.close() 
    return filename 
2

Vous pouvez créer un nouvel URLopener (hériter de FancyURLopener) et lancer des exceptions ou gérer les erreurs comme vous le souhaitez. Malheureusement, FancyURLopener ignore 404 et d'autres erreurs. Voir cette question:

How to catch 404 error in urllib.urlretrieve

6

Je le garde simple:

# Simple downloading with progress indicator, by Cees Timmerman, 16mar12. 

import urllib2 

remote = r"http://some.big.file" 
local = r"c:\downloads\bigfile.dat" 

u = urllib2.urlopen(remote) 
h = u.info() 
totalSize = int(h["Content-Length"]) 

print "Downloading %s bytes..." % totalSize, 
fp = open(local, 'wb') 

blockSize = 8192 #100000 # urllib.urlretrieve uses 8192 
count = 0 
while True: 
    chunk = u.read(blockSize) 
    if not chunk: break 
    fp.write(chunk) 
    count += 1 
    if totalSize > 0: 
     percent = int(count * blockSize * 100/totalSize) 
     if percent > 100: percent = 100 
     print "%2d%%" % percent, 
     if percent < 100: 
      print "\b\b\b\b\b", # Erase "NN% " 
     else: 
      print "Done." 

fp.flush() 
fp.close() 
if not totalSize: 
    print 
+0

Une meilleure idée est 'shutil.copyfileobj'. – lericson

+1

Comment ça, lericson? –

0
class MyURLopener(urllib.FancyURLopener): 
    http_error_default = urllib.URLopener.http_error_default 

url = "http://page404.com" 
filename = "download.txt" 
def reporthook(blockcount, blocksize, totalsize): 
    pass 
    ... 

try: 
    (f,headers)=MyURLopener().retrieve(url, filename, reporthook) 
except Exception, e: 
    print e 
0

:) Mon premier post sur StackOverflow, ont été Lurker pendant des années. :)

Malheureusement, dir (urllib.urlretrieve) est déficient en informations utiles. Donc de ce fil jusqu'ici j'essayé d'écrire ceci:

a,b = urllib.urlretrieve(imgURL, saveTo) 
print "A:", a 
print "B:", b 

qui a produit ceci:

A: /home/myuser/targetfile.gif 
B: Accept-Ranges: bytes 
Access-Control-Allow-Origin: * 
Cache-Control: max-age=604800 
Content-Type: image/gif 
Date: Mon, 07 Mar 2016 23:37:34 GMT 
Etag: "4e1a5d9cc0857184df682518b9b0da33" 
Last-Modified: Sun, 06 Mar 2016 21:16:48 GMT 
Server: ECS (hnd/057A) 
Timing-Allow-Origin: * 
X-Cache: HIT 
Content-Length: 27027 
Connection: close 

Je suppose que l'on peut vérifier:

if b.Content-Length > 0: 

Ma prochaine étape consiste à tester une scénario dans lequel la récupération échoue ...

+0

b.getheader ('Content-length') serait normalement supérieur à 0 même sur 404 (si le fichier n'existe pas) –

0

Résultats par rapport à un autre serveur/site Web - quoi revient dans « B » est un peu aléatoire, mais on peut tester pour certaines valeurs:

A: get_good.jpg 
B: Date: Tue, 08 Mar 2016 00:44:19 GMT 
Server: Apache 
Last-Modified: Sat, 02 Jan 2016 09:17:21 GMT 
ETag: "524cf9-18afe-528565aef9ef0" 
Accept-Ranges: bytes 
Content-Length: 101118 
Connection: close 
Content-Type: image/jpeg 

A: get_bad.jpg 
B: Date: Tue, 08 Mar 2016 00:44:20 GMT 
Server: Apache 
Content-Length: 1363 
X-Frame-Options: deny 
Connection: close 
Content-Type: text/html 

Dans le cas de « mauvais » (fichier image non existant) « B » récupéré un petit morceau de (Googlebot? Code HTML et enregistré en tant que cible, d'où Content-Length de 1363 octets.

Questions connexes