Python progress bar and downloads

前端 未结 10 1126
庸人自扰
庸人自扰 2020-11-28 02:28

I have a python script that launches a URL that is a downloadable file. Is there some way to have python use commandline to display the download progress as oppose to launch

相关标签:
10条回答
  • 2020-11-28 02:36

    The tqdm package now includes a function designed to handle exactly this type of situation: wrapattr. You just wrap an object's read (or write) attribute, and tqdm handles the rest. Here's a simple download function that puts it all together with 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
    
    0 讨论(0)
  • 2020-11-28 02:39

    Python 3 with TQDM

    This is the suggested technique from the 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)
    
    0 讨论(0)
  • 2020-11-28 02:40

    There is an answer with requests and tqdm.

    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)
    

    Gist: https://gist.github.com/yanqd0/c13ed29e29432e3cf3e7c38467f42f51

    0 讨论(0)
  • 2020-11-28 02:41

    You can stream a downloads as it is here -> Stream a Download.

    Also you can Stream Uploads.

    The most important streaming a request is done unless you try to access the response.content with just 2 lines

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

    Stream Requests

    0 讨论(0)
  • 2020-11-28 02:42

    I think you can also use click , and it has a good library for progress bar also.

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

    Enjoy !

    0 讨论(0)
  • 2020-11-28 02:44

    Sorry for being late with an answer; just updated the tqdm docs:

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

    Using urllib.urlretrieve and 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
    

    or using requests.get and file wrappers:

    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)
    

    You could of course mix & match techniques.

    0 讨论(0)
提交回复
热议问题