117 votes

Barre de progression Python et téléchargements

J'ai un script Python qui lance une URL qui est un fichier téléchargeable. Existe-t-il un moyen pour que Python affiche la progression du téléchargement plutôt que de lancer le navigateur ?

9voto

Tian Zhang Points 147

Vous pouvez également utiliser cliquez sur . Il dispose d'une bonne bibliothèque pour la barre de progression :

import click

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

8voto

abcdaa Points 1654

Désolé d'avoir répondu tardivement ; je viens de mettre à jour le site web de la Commission européenne. tqdm docs :

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

Utilisation de urllib.urlretrieve et 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

ou en utilisant requests.get et les enveloppes de fichiers :

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)

Vous pouvez bien sûr mélanger les techniques.

4voto

# Définir la fonction de la barre de progression

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)

# Exemple de code

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)

# Instantané de la barre de progression :

Les lignes ci-dessous ne sont que des illustrations. Dans l'invite de commande, vous verrez une seule barre de progression indiquant une progression incrémentale.

[ 0%............................................................] 1/6000

[ 16%..................................................] 1000/6000

[ 33%........................................] 2000/6000

[ 50%..............................] 3000/6000

[ 66%....................] 4000/6000

[ 83%..........] 5000/6000

[ 100%] 6000/6000

4voto

Mike Points 2409

En tqdm comprend désormais une fonction conçue pour gérer exactement ce type de situation : wrapattr . Il suffit d'envelopper l'objet read (ou write ), et tqdm s'occupe du reste. Voici une fonction de téléchargement simple qui met tout cela en place avec 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

0voto

Ehsan Ahmadi Points 4

Juste quelques améliorations de la réponse de @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")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X