2009-06-12 35 views
48

urllib.urlretrieve devuelve silenciosamente incluso si el archivo no existe en el servidor http remoto, solo guarda una página html en el archivo nombrado. Por ejemplo:¿Cómo saber si urllib.urlretrieve tiene éxito?

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

sólo devuelve en silencio, incluso si abc.jpg no existe en el servidor de google.com, el abc.jpg generado no es un archivo jpg válida, en realidad es una página HTML. Supongo que los encabezados devueltos (una instancia de httplib.HTTPMessage) se pueden usar para decir realmente si la recuperación tiene éxito o no, pero no puedo encontrar ningún documento para httplib.HTTPMessage.

¿Alguien puede proporcionar información sobre este problema?

Respuesta

22

Considere usar urllib2 si es posible en su caso. Es más avanzado y fácil de usar que urllib.

puede detectar cualquier error de HTTP fácilmente:

>>> 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 es en realidad HTTPResponse objeto que se puede hacer un montón de cosas útiles con:

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

¿Puede urllib2 proporcionar el comportamiento de almacenamiento en caché de urlretrieve? ¿O tendríamos que volver a implementarlo? – Kiv

+0

Vea este folleto fascinante de ActiveState: http://code.activestate.com/recipes/491261/ Lo estamos utilizando en nuestro proyecto actual, funciona perfectamente –

+1

urlopen no proporciona una función de enlace (para mostrar la barra de progreso de ejemplo) como urlretrieve. –

2

De acuerdo con la documentación que se está undocumented

para obtener acceso al mensaje parece que hacer algo como:

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

b es la instancia de mensaje

Desde que he aprendido que Python siempre es útil utilizar la capacidad de Python para ser introspectivo cuando escribo

dir(b) 

veo un montón de métodos o funciones jueguen con

Y entonces empecé a hacer cosas con b

por ejemplo

b.items() 

Listas un montón de cosas interesantes, sospecho que jugar con estas cosas le permitirán obtener el atributo que desea manipular.

Lo siento, esta es la respuesta de un principiante, pero estoy tratando de dominar cómo usar las habilidades de introspección para mejorar mi aprendizaje y sus preguntas simplemente aparecieron.

Bueno, hemos probado algo interesante relacionado con esto-me preguntaba si podía obtener automáticamente la salida de cada una de las cosas que se presentó en el directorio que no necesitaba parámetros así que escribí:

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

No tengo ningún estado, y tu código solo funciona una vez. Pruebe 'for k en b: print"% s:% r "% (k, b [k])' –

1

terminé con mi propia retrieve aplicación , con la ayuda de pycurl admite más protocolos que urllib/urllib2, espero que pueda ayudar a otras personas.

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

Puede crear un nuevo URLopener (heredar de FancyURLopener) y lanzar excepciones o controlar los errores de cualquier forma que desee. Desafortunadamente, FancyURLopener ignora 404 y otros errores. Ver esta pregunta:

How to catch 404 error in urllib.urlretrieve

6

lo guardo 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

Una mejor idea es 'shutil.copyfileobj'. – lericson

+1

¿Cómo es eso, 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

:) Mi primer post en StackOverflow, han sido un lurker durante años. :)

Sadly dir (urllib.urlretrieve) es deficiente en información útil. Así que de este tema hasta el momento he intentado escribir este:

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

que produjo este:

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 

supongo que uno puede comprobar:

if b.Content-Length > 0: 

Mi siguiente paso es poner a prueba una escenario donde la recuperación falla ...

+0

b.getheader ('Content-length') normalmente sería mayor que 0 incluso en 404 (si el archivo no existe) –

0

Resultados en otro servidor/sitio web - qué regresa en "B" es un poco al azar, pero se puede probar para ciertos valores:

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 

En el 'malo' caso (que no afecta a archivo de imagen) "B" recuperado una pequeña parte de (el robot de Google?) Código HTML y lo guardó como el objetivo, por lo tanto Content-Length de 1363 bytes.

Cuestiones relacionadas