2013-06-24 20 views
6

Chciałbym pobrać plik przez protokół HTTP przy użyciu urllib3. udało mi się zrobić to za pomocą następującego kodu:Jaki jest najlepszy sposób pobrania pliku za pomocą 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() 

Ale zastanawiałem się, co jest prawidłowe sposób to zrobić. Na przykład będzie działać dobrze w przypadku dużych plików i jeśli nie, co zrobić, aby ten kod był bardziej odporny na błędy i skalowalny.

Uwaga. Na przykład ważne jest, aby używać biblioteki urllib3, a nie urllib2, ponieważ chcę, aby mój kod był bezpieczny dla wątków.

Odpowiedz

14

Twój fragment kodu jest już blisko. Warto zauważyć dwie rzeczy:

  1. Jeśli używasz resp.data, będzie zużywać całą odpowiedź i powrót połączenia (nie trzeba do resp.release_conn() ręcznie). Jest to w porządku, jeśli chcesz przechowywać dane w pamięci.

  2. Można użyć resp.read(amt), które będzie transmitować odpowiedź, ale połączenie będzie musiało zostać zwrócone przez resp.release_conn().

To będzie wyglądać ...

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

Dokumentacja może być nieco brakuje na tym scenariuszu. Jeśli ktokolwiek jest zainteresowany zrobieniem pull-request to improve the urllib3 documentation, byłoby to bardzo cenne. :)

+0

Dobrze. Dziękuję za odpowiedź. –

+0

I jeszcze jedno pytanie. Czy będzie działać z metodą POST, jeśli dodaję 'r = http.request ('POST', url)'? –

+0

@ running.t Err, to był błąd w moim kodzie. Masz rację, metoda powinna iść pierwsza, a twój fragment będzie działał. (Zaktualizowałem moją odpowiedź.) – shazow

-2

dodatek o nazwie zmienna preload_content inny mógłby skończyć się pobierając pełną treść

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

@ 2Dee: Czy możesz mi powiedzieć, co jest nie tak, więc mogłem poprawić siebie – giridhar

+1

Myślę, że podczas gdy twoja odpowiedź może być poprawna (nie jestem zaznajomiony z urllib3), wydaje się, że nie udało się w pełni odpowiedzieć na zadane pytanie. To powiedziawszy, nie zagłosowałem na twoją odpowiedź, jeśli widzisz moje imię pojawiające się pod postem, to tylko dlatego, że zredagowałem twoją odpowiedź, aby kod był poprawnie sformatowany. Mając nadzieję, że to sprawi, że sprawy będą bardziej przejrzyste;) – 2Dee

2

Najbardziej poprawny sposób to zrobić, prawdopodobnie, aby uzyskać obiekt plikopodobny reprezentującą odpowiedzi HTTP i skopiuj go do prawdziwego pliku przy użyciu pliku shutil.copyfileobj, jak poniżej:

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 
Powiązane problemy