2009-10-04 11 views
50

Io uso il seguente codice per lo streaming di file di grandi dimensioni da Internet in un file locale:stream grandi file binari con urllib2 su file

fp = open(file, 'wb') 
req = urllib2.urlopen(url) 
for line in req: 
    fp.write(line) 
fp.close() 

Questo funziona, ma si scarica molto lentamente. C'è un modo più veloce? (I file sono grandi quindi non li voglio conservare in memoria.)

+2

Se solo questo è stato costruito come un unico comando, ad es 'urllib.urldownload (url, file)' –

+0

@GeraldKaszuba: intendi come ['urllib.urlretrieve (url, file)'] (http://docs.python.org/2/library/urllib.html#urllib. urlrire) – jfs

+0

@JFSebastian Bello! Forse postarlo come risposta? –

risposta

94

Non c'è ragione di lavorare riga per riga, solo pezzo fino a pezzi più grandi, ad esempio:

# from urllib2 import urlopen # Python 2 
from urllib.request import urlopen # Python 3 

response = urlopen(url) 
CHUNK = 16 * 1024 
with open(file, 'wb') as f: 
    while True: 
     chunk = response.read(CHUNK) 
     if not chunk: 
      break 
     f.write(chunk) 

sperimentare un po 'con i vari Dimensioni CHUNK per trovare il "punto debole" per le tue esigenze.

+0

grazie Alex - sembra che questo fosse il mio problema perché la maggior parte delle linee erano solo poche centinaia di byte. – hoju

+2

ha funzionato per me. Ma penso che fp.close() manchi ancora – printminion

+6

russenreaktor, usando il con open (...) come ...: ha un implicito close() chiamato dopo aver lasciato l'istruzione with. – mklauber

6

Ho usato il modulo mechanize e il suo metodo Browser.retrieve(). In passato ci sono voluti CPU al 100% e le cose sono state scaricate molto lentamente, ma alcune recenti versioni hanno risolto questo bug e funzionavano molto rapidamente.

Esempio:

import mechanize 
browser = mechanize.Browser() 
browser.retrieve('http://www.kernel.org/pub/linux/kernel/v2.6/testing/linux-2.6.32-rc1.tar.bz2', 'Downloads/my-new-kernel.tar.bz2') 

Mechanize è basata su urllib2, in modo urllib2 può anche avere metodo simile ... ma non riesco a trovare qualsiasi ora. (! Piccoli pezzi e richiede Python per trovare la linea termina per voi -)

+0

fa approssimativamente lo stesso proposto da Alex Martinelly; 'BLOCK_SIZE' = 8 * 1024 ed è normalmente risolto –

58

È inoltre possibile utilizzare shutil:

import shutil 
try: 
    from urllib.request import urlopen # Python 3 
except ImportError: 
    from urllib2 import urlopen # Python 2 

def get_large_file(url, file, length=16*1024): 
    req = urlopen(url) 
    with open(file, 'wb') as fp: 
     shutil.copyfileobj(req, fp, length) 
+0

+1, questo fa esattamente la stessa cosa suggerita da Alex Martelli. E accetta il parametro 'length' (' shutil.copyfileobj (fsrc, fdst [, length]) ') che è anche = 16 * 1024 di default –

3

È possibile utilizzare urllib.retrieve() per scaricare i file:

Esempio:

try: 
    from urllib import urlretrieve # Python 2 

except ImportError: 
    from urllib.request import urlretrieve # Python 3 

url = "http://www.examplesite.com/myfile" 
urlretrieve(url,"./local_file") 
+3

Probabilmente intendevi' urllib.urlretrieve (url, "./ local_file") ' – Blairg23