2010-08-20 35 views
6

Sto tentando di scaricare un file zip utilizzando questo codice:Python: Come scaricare un file zip

o = urllib2.build_opener(urllib2.HTTPCookieProcessor()) 

#login 
p = urllib.urlencode({ usernameField: usernameVal, passField: passVal }) 
f = o.open(authUrl, p) 
data = f.read() 
print data 
f.close() 

#download file 
f = o.open(remoteFileUrl) 
localFile = open(localFile, "wb") 
localFile.write(f.read()) 
f.close() 

io sono sempre alcuni dati binari, ma la dimensione del file "scaricato" è troppo piccolo e non è un file zip valido. Non sto recuperando il file zip correttamente? L'intestazione della risposta HTTP per f = o.open(remoteFileUrl) è mostrata di seguito. Non so se è necessaria l'elaborazione speciale per gestire questa risposta:

HTTP/1.1 200 OK Server: Apache
-Coyote/1.1 Pragma: privato
Cache-Control: must-rinnovare
Scade : Mar, 31 dic 1997 23:59:59 GMT
Content-Disposition: inline;
filename = "files.zip";
Content-Type: application/zip
Transfer-Encoding: chunked

risposta

10

f.read() non necessariamente leggere l'intero file, ma solo un pacchetto di esso (che potrebbe essere l'intero file se è piccola, ma non sarà per un file di grandi dimensioni).

È necessario un ciclo su pacchetti come questo:

while 1: 
    packet = f.read() 
    if not packet: 
     break 
    localFile.write(packet) 
f.close() 

f.read() restituisce un pacchetto vuoto per indicare che hai letto l'intero file.

+2

Sarei curioso in cui sono nella documentazione trovato questo –

+0

http://docs.python.org/library/urllib.html#urllib.urlopen: "viene restituito un oggetto simile a un file" quindi http://docs.python.org/library/stdtypes.html#file .read – RichieHindle

+0

davvero solo un pacchetto? Ho controllato i documenti al link mostrato e non vedo da nessuna parte che dice che read() non legge fino a EOF. puoi spiegare di più? –

1

Se non ti dispiace leggere l'intero file zip alla memoria, il modo più veloce per leggere e scrivere è la seguente:

data = f.readlines() 
with open(localFile,'wb') as output: 
    output.writelines(data) 

In caso contrario, a leggere e scrivere in blocchi come li si ottiene via rete, fare

with open(localFile, "wb") as output: 
    chunk = f.read() 
    while chunk: 
     output.write(chunk) 
     chunk = f.read() 

Questo è un po 'meno pulito, ma evita di mantenere l'intero file in memoria in una volta. Spero che sia d'aiuto.

0

Prova questo:

#download file 
f = o.open(remoteFileUrl) 

response = "" 
while 1: 
    data = f.read() 
    if not data: 
     break 
    response += data 

with open(localFile, "wb") as local_file: 
    local_file.write(response) 
1

Ecco una soluzione più robusta utilizzando urllib2 per scaricare il file in blocchi e stampare lo stato del download

import os 
import urllib2 
import math 

def downloadChunks(url): 
    """Helper to download large files 
     the only arg is a url 
     this file will go to a temp directory 
     the file will also be downloaded 
     in chunks and print out how much remains 
    """ 

    baseFile = os.path.basename(url) 

    #move the file to a more uniq path 
    os.umask(0002) 
    temp_path = "/tmp/" 
    try: 
     file = os.path.join(temp_path,baseFile) 

     req = urllib2.urlopen(url) 
     total_size = int(req.info().getheader('Content-Length').strip()) 
     downloaded = 0 
     CHUNK = 256 * 10240 
     with open(file, 'wb') as fp: 
      while True: 
       chunk = req.read(CHUNK) 
       downloaded += len(chunk) 
       print math.floor((downloaded/total_size) * 100) 
       if not chunk: break 
       fp.write(chunk) 
    except urllib2.HTTPError, e: 
     print "HTTP Error:",e.code , url 
     return False 
    except urllib2.URLError, e: 
     print "URL Error:",e.reason , url 
     return False 

    return file 
+0

Sarà robusto solo se si gestisce il caso in cui non viene inviata l'intestazione "Content-Lenght" IMO –

+0

Good point Xavier – Gourneau

Problemi correlati