2013-06-24 161 views
6

我想用urllib3通過HTTP協議下載文件。 我已成功地做到這一點使用下面的代碼:什麼是使用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() 

但我想知道什麼是這樣做的適當方式。 例如,它可以很好地處理大文件,並且如果沒有該做什麼來使這些代碼更具有容錯性和可擴展性。

注意。例如,使用urllib3庫不是urllib2對我來說很重要,因爲我希望我的代碼是線程安全的。

回答

14

您的代碼片段已關閉。值得一提的有兩兩件事:

  1. 如果您使用resp.data,它會消耗整個響應並返回連接(你沒有需要手動resp.release_conn())。如果你把數據保存在內存中很酷,這很好。

  2. 您可以使用resp.read(amt)這將傳輸響應,但連接將需要通過resp.release_conn()返回。

這看起來是這樣的......

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

該文檔可能會有點欠缺這種方案。如果有人有興趣製作pull-request to improve the urllib3 documentation,那將不勝感激。命名變量:)

+0

那麼。謝謝你的回答。 –

+0

還有一個問題。如果我添加'r = http.request('POST',url)'',它會與POST方法一起工作嗎? –

+0

@ running.t錯誤,這是我的代碼中的錯誤。你是對的,該方法應該先行,你的代碼段將起作用。 (更新了我的答案。) – shazow

-2

附加preload_content否則你最終將下載全部內容

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

@ 2Dee:你能否告訴我這裏有什麼問題,這樣我就可以糾正自己 – giridhar

+1

我認爲,雖然你的回答可能是正確的(我對urllib3不熟悉),但似乎沒有完全解決問題。也就是說,我沒有把你的答案投下來,如果你看到我的名字出現在帖子下,那只是因爲我編輯了你的答案,所以代碼將被正確格式化。希望這可以讓你更清楚;) – 2Dee

2

最正確的方式做到這一點可能是獲取表示HTTP響應一個類似文件的對象,並將其複製使用shutil.copyfileobj到一個真實的文件如下:

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 
相關問題