【问题标题】:Python progress bar and downloadsPython 进度条和下载
【发布时间】:2013-03-16 17:08:44
【问题描述】:

我有一个 Python 脚本,它启动一个可下载文件的 URL。有没有办法让 Python 显示下载进度而不是启动浏览器?

【问题讨论】:

标签: python download progress-bar


【解决方案1】:

我刚刚为此编写了一个超级简单(有点笨拙)的方法,用于从某个站点上抓取 PDF。请注意,它只能在基于 Unix 的系统(Linux、mac os)上正常工作,因为 PowerShell 无法处理 "\r"

import sys
import requests

link = "http://indy/abcde1245"
file_name = "download.data"
with open(file_name, "wb") as f:
    print("Downloading %s" % file_name)
    response = requests.get(link, stream=True)
    total_length = response.headers.get('content-length')

    if total_length is None: # no content length header
        f.write(response.content)
    else:
        dl = 0
        total_length = int(total_length)
        for data in response.iter_content(chunk_size=4096):
            dl += len(data)
            f.write(data)
            done = int(50 * dl / total_length)
            sys.stdout.write("\r[%s%s]" % ('=' * done, ' ' * (50-done)) )    
            sys.stdout.flush()

它使用requests library,因此您需要安装它。这会在您的控制台中输出如下内容:

>正在下载download.data

>[=============                           ]

脚本中的进度条有 52 个字符宽(2 个字符就是 [],所以进度条有 50 个字符)。每个= 代表下载量的 2%。

【讨论】:

  • 我也有同样的问题,什么是pdf?
  • 你可能想在 iter_content 中定义 chunk_size,这样就不会那么慢了。
  • 正如@0942v8653 所提到的,iter_content() 需要一个 chunk_size,因此您可以指定它以提高速度,但如果您下载的内容足够小,大约 1% 可以放入内存,您通过执行 chunk_size=total_length/100 可以大大简化您的代码,并且循环的每次迭代将是您下载量的 1%
  • 在 Windows 上为我工作。还将一行从for data in response.iter_content(): 更改为for data in response.iter_content(chunk_size=total_length/100):
  • 据我所知,Windows 10 上的命令行确实支持\r
【解决方案2】:

您可以使用“clint”包(由与“请求”相同的作者编写)为您的下载添加一个简单的进度条,如下所示:

from clint.textui import progress

r = requests.get(url, stream=True)
path = '/some/path/for/file.txt'
with open(path, 'wb') as f:
    total_length = int(r.headers.get('content-length'))
    for chunk in progress.bar(r.iter_content(chunk_size=1024), expected_size=(total_length/1024) + 1): 
        if chunk:
            f.write(chunk)
            f.flush()

这将为您提供如下所示的动态输出:

[################################] 5210/5210 - 00:00:01

它应该也可以在多个平台上运行!你 can also change 条形到点或带有 .dots 和 .mill 而不是 .bar 的微调器。

享受吧!

【讨论】:

  • 如果它可以成为python标准库的一部分就好了。
  • path 是您要保存文件的文件名。
  • path = "filename.ext"
  • Clint 现已停产
  • 评论当我不可避免地想回到这个 - 这太棒了!
【解决方案3】:

带有 TQDM 的 Python 3

这是来自TQDM docs 的建议技术。

import urllib.request

from tqdm import tqdm


class DownloadProgressBar(tqdm):
    def update_to(self, b=1, bsize=1, tsize=None):
        if tsize is not None:
            self.total = tsize
        self.update(b * bsize - self.n)


def download_url(url, output_path):
    with DownloadProgressBar(unit='B', unit_scale=True,
                             miniters=1, desc=url.split('/')[-1]) as t:
        urllib.request.urlretrieve(url, filename=output_path, reporthook=t.update_to)

【讨论】:

  • 这是迄今为止最好的。
【解决方案4】:

requeststqdm 有答案。

import requests
from tqdm import tqdm


def download(url: str, fname: str):
    resp = requests.get(url, stream=True)
    total = int(resp.headers.get('content-length', 0))
    with open(fname, 'wb') as file, tqdm(
        desc=fname,
        total=total,
        unit='iB',
        unit_scale=True,
        unit_divisor=1024,
    ) as bar:
        for data in resp.iter_content(chunk_size=1024):
            size = file.write(data)
            bar.update(size)

要点:https://gist.github.com/yanqd0/c13ed29e29432e3cf3e7c38467f42f51

【讨论】:

    【解决方案5】:

    您也可以使用click。它有一个很好的进度条库:

    import click
    
    with click.progressbar(length=total_size, label='Downloading files') as bar:
        for file in files:
            download(file)
            bar.update(file.size)
    

    【讨论】:

    • @MortenB 是吗?我在 3.6.1 收到 ModuleNotFoundError: No module named 'click'
    • 这是一个需要安装的第二方库
    • @AbdealiJK 第三方
    • 什么是“total_size”?
    • @MortenB 先做pip install click,然后执行代码?
    【解决方案6】:

    抱歉回复晚了;刚刚更新了tqdm 文档:

    https://github.com/tqdm/tqdm/#hooks-and-callbacks

    使用 urllib.urlretrieve 和 OOP:

    import urllib
    from tqdm.auto import tqdm
    
    class TqdmUpTo(tqdm):
        """Provides `update_to(n)` which uses `tqdm.update(delta_n)`."""
        def update_to(self, b=1, bsize=1, tsize=None):
            """
            b  : Blocks transferred so far
            bsize  : Size of each block
            tsize  : Total size
            """
            if tsize is not None:
                self.total = tsize
            self.update(b * bsize - self.n)  # will also set self.n = b * bsize
    
    eg_link = "https://github.com/tqdm/tqdm/releases/download/v4.46.0/tqdm-4.46.0-py2.py3-none-any.whl"
    eg_file = eg_link.split('/')[-1]
    with TqdmUpTo(unit='B', unit_scale=True, unit_divisor=1024, miniters=1,
                  desc=eg_file) as t:  # all optional kwargs
        urllib.urlretrieve(
            eg_link, filename=eg_file, reporthook=t.update_to, data=None)
        t.total = t.n
    

    或使用requests.get 和文件包装器:

    import requests
    from tqdm.auto import tqdm
    
    eg_link = "https://github.com/tqdm/tqdm/releases/download/v4.46.0/tqdm-4.46.0-py2.py3-none-any.whl"
    eg_file = eg_link.split('/')[-1]
    response = requests.get(eg_link, stream=True)
    with tqdm.wrapattr(open(eg_file, "wb"), "write", miniters=1,
                       total=int(response.headers.get('content-length', 0)),
                       desc=eg_file) as fout:
        for chunk in response.iter_content(chunk_size=4096):
            fout.write(chunk)
    

    你当然可以混搭技巧。

    【讨论】:

      【解决方案7】:

      另一个不错的选择是wget:

      import wget
      wget.download('http://download.geonames.org/export/zip/US.zip')
      

      输出将如下所示:

      11% [........                                     ] 73728 / 633847
      

      来源:https://medium.com/@petehouston/download-files-with-progress-in-python-96f14f6417a2

      【讨论】:

        【解决方案8】:

        tqdm 包现在包含一个专门用于处理此类情况的函数:wrapattr。您只需包装对象的read(或write)属性,其余的由tqdm 处理。这是一个简单的下载功能,将所有内容与requests 放在一起:

        def download(url, filename):
            import functools
            import pathlib
            import shutil
            import requests
            import tqdm
            
            r = requests.get(url, stream=True, allow_redirects=True)
            if r.status_code != 200:
                r.raise_for_status()  # Will only raise for 4xx codes, so...
                raise RuntimeError(f"Request to {url} returned status code {r.status_code}")
            file_size = int(r.headers.get('Content-Length', 0))
        
            path = pathlib.Path(filename).expanduser().resolve()
            path.parent.mkdir(parents=True, exist_ok=True)
        
            desc = "(Unknown total file size)" if file_size == 0 else ""
            r.raw.read = functools.partial(r.raw.read, decode_content=True)  # Decompress if needed
            with tqdm.tqdm.wrapattr(r.raw, "read", total=file_size, desc=desc) as r_raw:
                with path.open("wb") as f:
                    shutil.copyfileobj(r_raw, f)
        
            return path
        

        【讨论】:

        • 必须
        【解决方案9】:

        #定义进度条功能

        def print_progressbar(total, current, barsize=60):
            progress = int(current*barsize/total)
            completed = str(int(current*100/total)) + '%'
            print('[', chr(9608)*progress, ' ', completed, '.'*(barsize-progress), '] ', str(i)+'/'+str(total), sep='', end='\r', flush=True)
        

        # 示例代码

        total = 6000
        barsize = 60
        print_frequency = max(min(total//barsize, 100), 1)
        print("Start Task..", flush=True)
        for i in range(1, total+1):
          if i%print_frequency == 0 or i == 1:
            print_progressbar(total, i, barsize)
        print("\nFinished", flush=True)
        

        #进度条截图:

        以下行仅用于说明。在命令提示符下,您将看到显示增量进度的单个进度条。

        [ 0%............................................................] 1/6000
        
        [██████████ 16%..................................................] 1000/6000
        
        [████████████████████ 33%........................................] 2000/6000
        
        [██████████████████████████████ 50%..............................] 3000/6000
        
        [████████████████████████████████████████ 66%....................] 4000/6000
        
        [██████████████████████████████████████████████████ 83%..........] 5000/6000
        
        [████████████████████████████████████████████████████████████ 100%] 6000/6000
        

        【讨论】:

          【解决方案10】:

          只是对@rich-jones 回答的一些改进

           import re
           import request
           from clint.textui import progress
          
           def get_filename(cd):
              """
              Get filename from content-disposition
              """
              if not cd:
                  return None
              fname = re.findall('filename=(.+)', cd)
              if len(fname) == 0:
                  return None
              return fname[0].replace('"', "")
          
          def stream_download_file(url, output, chunk_size=1024, session=None, verbose=False):
              
              if session:
                  file = session.get(url, stream=True)
              else:
                  file = requests.get(url, stream=True)
                  
              file_name = get_filename(file.headers.get('content-disposition'))
              filepath = "{}/{}".format(output, file_name)
              
              if verbose: 
                  print ("Downloading {}".format(file_name))
                  
              with open(filepath, 'wb') as f:
                  total_length = int(file.headers.get('content-length'))
                  for chunk in progress.bar(file.iter_content(chunk_size=chunk_size), expected_size=(total_length/chunk_size) + 1): 
                      if chunk:
                          f.write(chunk)
                          f.flush()
              if verbose: 
                  print ("Finished")
          

          【讨论】:

            【解决方案11】:

            您可以在此处流式传输下载 -> Stream a Download

            你也可以Stream Uploads

            除非您尝试访问 response.content,否则最重要的流式请求已完成 只有 2 行

            for line in r.iter_lines():    
                if line:
                    print(line)
            

            Stream Requests

            【讨论】:

              猜你喜欢
              • 2018-01-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-12-20
              • 1970-01-01
              相关资源
              最近更新 更多