2013-06-24 7 views
6

Vorrei scaricare il file tramite il protocollo HTTP utilizzando urllib3. Sono riuscito a fare questo seguente codice utilizzando:Qual è il modo migliore per scaricare il file utilizzando urllib3

url = 'http://url_to_a_file' 
connection_pool = urllib3.PoolManager() 
resp = connection_pool.request('GET',url) 
f = open(filename, 'wb') 
f.write(resp.data) 
f.close() 
resp.release_conn() 

ma mi chiedevo che cosa è la corretta modo di fare questo. Ad esempio, funzionerà bene per i file di grandi dimensioni e se non c'è alcuno da fare per rendere questo codice più tollerante ai bug e scalabile.

Nota. Per me è importante usare la libreria urllib3 non urllib2 perché voglio che il mio codice sia sicuro per i thread.

risposta

14

Il tuo snippet di codice è chiuso. Due cose degne di nota:

  1. Se stai usando resp.data, si consumerà l'intera risposta e restituire il collegamento (non è necessario per resp.release_conn() manualmente). Questo va bene se sei bravo a tenere i dati in memoria.

  2. È possibile utilizzare resp.read(amt) che trasmetterà la risposta, ma la connessione dovrà essere restituita tramite resp.release_conn().

Questo sarebbe simile ...

import urllib3 
http = urllib3.PoolManager() 
r = http.request('GET', url, preload_content=False) 

with open(path, 'wb') as out: 
    while True: 
     data = r.read(chunk_size) 
     if not data: 
      break 
     out.write(data) 

r.release_conn() 

La documentazione potrebbe essere un po 'carente su questo scenario. Se qualcuno è interessato a fare un pull-request to improve the urllib3 documentation, sarebbe molto apprezzato. :)

+0

Bene. Grazie per la risposta. –

+0

E un'altra domanda. Funzionerà con il metodo POST se aggiungo 'r = http.request ('POST', url)'? –

+0

@ running.t Err, è stato un errore nel mio codice. Hai ragione, il metodo dovrebbe andare per primo e il tuo frammento funzionerà. (Aggiornato la mia risposta.) – shazow

-2

aggiuntivo di nome variabile preload_content altrimenti si finirebbe per scaricare l'intero contenuto

http.request('GET', url, preload_content=False) 
+0

@ 2Dee: Potresti dirmi cosa c'è di sbagliato qui in modo da poter correggere me stesso – giridhar

+1

Penso che, mentre la tua risposta potrebbe essere corretta (non ho familiarità con urllib3), sembra non riuscire a rispondere pienamente alla domanda posta. Detto questo, non ho votato la tua risposta, se vedi che il mio nome appare sotto il post, è solo perché ho modificato la tua risposta in modo che il codice sia formattato correttamente. Sperando che ciò abbia reso le cose più chiare per te;) – 2Dee

2

il modo più corretto per farlo è probabilmente per ottenere un oggetto simile a file che rappresenta la risposta HTTP e copiarlo a un file reale utilizzando shutil.copyfileobj come di seguito:

url = 'http://url_to_a_file' 
c = urllib3.PoolManager() 

with c.request('GET',url, preload_content=False) as resp, open(filename, 'wb') as out_file: 
    shutil.copyfileobj(resp, out_file) 

resp.release_conn()  # not 100% sure this is required though 
Problemi correlati