2014-07-10 18 views
11

我正在使用請求從服務器下載文件(幾個千兆字節)。爲了提供進度更新(並防止整個文件不必存儲在內存中),我給自己定stream=True寫下了下載到文件:避免使用請求2.3.0的空塊的ChunkedEncodingError 2.3.0

with open('output', 'w') as f: 
    response = requests.get(url, stream=True) 

    if not response.ok: 
     print 'There was an error' 
     exit() 

    for block in response.iter_content(1024 * 100): 
     f.write(block) 
     completed_bytes += len(block) 
     write_progress(completed_bytes, total_bytes) 

然而,在一些隨機點在下載,請求拋出一個ChunkedEncodingError。我已經進入源代碼,發現this corresponds to an IncompleteRead exception。我在這些行中插入了一條日誌語句,並發現e.partial = "\r"。我知道服務器給予下載低優先級,我懷疑當服務器等待太長時間發送下一個塊時會發生此異常。

如預期的那樣,異常停止下載。不幸的是,服務器沒有實現HTTP/1.1的內容範圍,所以我不能簡單地恢復它。我玩過urllib3的內部超時,但異常仍然存在。

有沒有辦法使底層urllib3(或請求)更容忍這些空(或晚)塊,以便該文件可以完全下載?

+0

你在哪個平臺上?我可以建議使用一種可以專門用於你的使用的工具,你可以通過shell調用,比如捲曲嗎? –

+0

你可以嘗試在get中設置更長的超時時間(kwarg超時應該在2.3中使用stream = True,請參閱https://github.com/kennethreitz/requests/issues/1803)。我還會驗證你的頭文件的內容類型和編碼是否符合你期望的要求,以確保它不會截斷流 –

+0

你試過了一個更小的塊嗎?好像我一直使用1024或2048。 – Wyrmwood

回答

1
import httplib 

def patch_http_response_read(func): 
    def inner(*args): 
     try: 
      return func(*args) 
     except httplib.IncompleteRead, e: 
      return e.partial 
    return inner 

httplib.HTTPResponse.read = patch_http_response_read(httplib.HTTPResponse.read) 

我現在不能重現您的問題,但我認爲這可能是一個補丁。它允許你處理有缺陷的http服務器。

大多數不良服務器傳輸所有數據,但由於執行錯誤,他們錯誤地關閉會話和httplib引發錯誤並埋葬您寶貴的字節。