2009-10-04 11 views
50

używam następujący kod do przesyłania dużych plików z Internetu do lokalnego pliku:Stream duże pliki binarne z urllib2 złożyć

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

to działa, ale pobiera dość powoli. Czy jest szybszy sposób? (Pliki są duże, więc nie chcę ich przechowywać w pamięci).

+2

Gdyby tylko ten został zbudowany jako pojedyncza polecenie, np 'urllib.urldownload (url, file)' –

+0

@GeraldKaszuba: masz na myśli ['urllib.urlretrieve (url, file)'] (http://docs.python.org/2/library/urllib.html#urllib. urlretrieve) – jfs

+0

@JFSebastian Nice! Może możesz to opublikować jako odpowiedź? –

Odpowiedz

94

Nie ma powodu, aby pracować linia po linii, po prostu kawałek go w większych kawałkach, np:

# 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) 

Eksperyment nieco z różnymi CHUNK rozmiary, aby znaleźć "słodki punkt" dla swoich potrzeb.

+0

dzięki Alex - wygląda na to, że to był mój problem, ponieważ większość linii miała tylko kilkaset bajtów. – hoju

+2

to zadziałało dla mnie. Ale myślę, że nadal brakuje fp.close() – printminion

+6

russenreaktor, używając z open (...) jako ...: ma niejawne close() wywołane po opuszczeniu instrukcji with. – mklauber

6

Użyłem kiedyś modułu mechanize i jego metody Browser.retrieve(). W przeszłości wymagało to 100% procesora i pobierane rzeczy bardzo powoli, ale niektóre najnowsze wersje naprawiły ten błąd i działają bardzo szybko.

Przykład:

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 jest oparta na urllib2, więc urllib2 może mieć podobny sposób ... ale nie mogę znaleźć żadnego teraz. (! Małe kawałki i wymaga Python znaleźć linia kończy się dla ciebie -)

+0

robi mniej więcej to samo, co sugerował Alex Martinelly; 'BLOCK_SIZE' = 8 * 1024 i jest zwykle ustalany –

58

Można również użyć 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, robi to dokładnie tak samo, jak sugerował Alex Martelli. I akceptuje parametr 'length' (' shutil.copyfileobj (fsrc, fdst [, length]) '), który jest również = 16 * 1024 domyślnie –

3

Można użyć urllib.retrieve(), aby pobrać pliki:

Przykład:

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

Prawdopodobnie miałeś na myśli' urllib.urlretrieve (url, ./ local_file ") ' – Blairg23

Powiązane problemy