Python3使用requests模塊顯示下載進度

出處:http://blog.csdn.net/supercooly/article/details/51046561

一、配置request
1. 相關資料

請求關鍵參數:stream=True。默認情況下,當你進行網絡請求後,響應體會立即被下載。你可以通過 stream 參數覆蓋這個行爲,推遲下載響應體直到訪問 Response.content 屬性。

tarball_url = 'https://github.com/kennethreitz/requests/tarball/master'
r = requests.get(tarball_url, stream=True)

此時僅有響應頭被下載下來了,連接保持打開狀態,因此允許我們根據條件獲取內容:

if int(r.headers['content-length']) < TOO_LONG:
  content = r.content
  ...

進一步使用 Response.iter_content 和 Response.iter_lines 方法來控制工作流,或者以 Response.raw 從底層urllib3的 urllib3.HTTPResponse

from contextlib import closing

with closing(requests.get('http://httpbin.org/get', stream=True)) as r:
    # Do things with the response here.

保持活動狀態(持久連接)
歸功於urllib3,同一會話內的持久連接是完全自動處理的,同一會話內發出的任何請求都會自動複用恰當的連接!

注意:只有當響應體的所有數據被讀取完畢時,連接纔會被釋放到連接池;所以確保將 stream 設置爲 False 或讀取 Response 對象的 content 屬性。
2. 下載文件並顯示進度條

with closing(requests.get(self.url(), stream=True)) as response:
    chunk_size = 1024 # 單次請求最大值
    content_size = int(response.headers['content-length']) # 內容體總大小
    progress = ProgressBar(self.file_name(), total=content_size,
                                     unit="KB", chunk_size=chunk_size, run_status="正在下載", fin_status="下載完成")
    with open(file_name, "wb") as file:
       for data in response.iter_content(chunk_size=chunk_size):
           file.write(data)
           progress.refresh(count=len(data))

二、進度條類的實現

在Python3中,print()方法的默認結束符(end=’\n’),當調用完之後,光標自動切換到下一行,此時就不能更新原有輸出。

將結束符改爲“\r”,輸出完成之後,光標會回到行首,並不換行。此時再次調用print()方法,就會更新這一行輸出了。

結束符也可以使用“\d”,爲退格符,光標回退一格,可以使用多個,按需求回退。

在結束這一行輸出時,將結束符改回“\n”或者不指定使用默認

下面是一個格式化的進度條顯示模塊。代碼如下:


class ProgressBar(object):

    def __init__(self, title,
                 count=0.0,
                 run_status=None,
                 fin_status=None,
                 total=100.0,
                 unit='', sep='/',
                 chunk_size=1.0):
        super(ProgressBar, self).__init__()
        self.info = "【%s】%s %.2f %s %s %.2f %s"
        self.title = title
        self.total = total
        self.count = count
        self.chunk_size = chunk_size
        self.status = run_status or ""
        self.fin_status = fin_status or " " * len(self.statue)
        self.unit = unit
        self.seq = sep

    def __get_info(self):
        # 【名稱】狀態 進度 單位 分割線 總數 單位
        _info = self.info % (self.title, self.status,
                             self.count/self.chunk_size, self.unit, self.seq, self.total/self.chunk_size, self.unit)
        return _info

    def refresh(self, count=1, status=None):
        self.count += count
        # if status is not None:
        self.status = status or self.status
        end_str = "\r"
        if self.count >= self.total:
            end_str = '\n'
            self.status = status or self.fin_status
        print(self.__get_info(), end=end_str)


三、參考資料

http://www.gaoxuewen.cn/index.php/python/1086.html
http://cn.python-requests.org/en/latest/user/advanced.html


--------------------------------------------------------以下是本人整理-----------------------------------------------------------------------------------------------------------

代碼整理:

# @autho:[email protected]
class ProgressBar(object):
    def __init__(self, title, count=0.0, run_status=None, fin_status=None, total=100.0,    unit='', sep='/', chunk_size=1.0):
        super(ProgressBar, self).__init__()
        self.info = "[%s] %s %.2f %s %s %.2f %s"
        self.title = title
        self.total = total
        self.count = count
        self.chunk_size = chunk_size
        self.status = run_status or ""
        self.fin_status = fin_status or " " * len(self.statue)
        self.unit = unit
        self.seq = sep

    def __get_info(self):
        # 【名稱】狀態 進度 單位 分割線 總數 單位
        _info = self.info % (self.title, self.status, self.count/self.chunk_size, self.unit, self.seq, self.total/self.chunk_size, self.unit)
        return _info

    def refresh(self, count=1, status=None):
        self.count += count
        # if status is not None:
        self.status = status or self.status
        end_str = "\r"
        if self.count >= self.total:
            end_str = '\n'
            self.status = status or self.fin_status
            

        """
        沒搞懂 print(end="")的用法
        ,在eric中打印的東西看不到
        ,在window控制檯下單條語句刷新並不添加新的行
        """  
        # print(,end="")的用法,可能會出現打印看不到的情況
        print(self.__get_info(), end=end_str, )


if __name__ == '__main__':
    
    import requests
    from contextlib import closing
    
    url ="http://big1.wy119.com/mingw-w64.zip"

    with closing(requests.get(url, stream=True)) as response:
        chunk_size = 1024
        content_size = int(response.headers['content-length'])
        """
        需要根據 response.status_code 的不同添加不同的異常處理
        """
        print('content_size', content_size,response.status_code ,  )
        progress = ProgressBar("razorback"
                    , total=content_size
                    , unit="KB"
                    , chunk_size=chunk_size
                    , run_status="正在下載"
                    , fin_status="下載完成")
            # chunk_size = chunk_size < content_size and chunk_size or content_size
        with open('./file.zip', "wb") as file:
                for data in response.iter_content(chunk_size=chunk_size):
                    file.write(data)
                    progress.refresh(count=len(data))
                    
        print('下載完成', )
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章