Показать индикатор выполнения для загрузки и скачивания файлов
Введение:
В этой статье мы обсудим улучшение взаимодействия с пользователем с помощью Python. При этом наиболее важным пользовательским опытом, который мы можем предоставить, является визуальная подсказка или уведомление пользователя о ходе выполнения задачи или действия.
На мой взгляд, загрузка и скачивание файлов через HTTP являются наиболее распространенными вариантами использования, с которыми столкнется каждый разработчик Python. Если вы еще этого не сделали, сохраните страницу. Вы можете столкнуться с одним из таких случаев когда-нибудь. 🙂
Значение этой статьи заключается в отображении индикатора выполнения с помощью tqdm, и мы сосредоточимся на tqdm, а не на загрузке или выгрузке файлов.
Забрать:
В конце этой статьи вы должны быть в состоянии
- Отображение индикатора выполнения с помощью tqdm для загрузки файлов
- Отображение индикатора выполнения с помощью tqdm для загрузки файлов
- Иметь базовое представление о библиотеке tqdm
тквдм:
tqdm
означает "прогресс" по-арабски (taqadum, تقدّم) и является аббревиатурой от "я так тебя люблю" по-испански (te quiero demasiado). - Из документов
Использование tqdm для отображения индикатора выполнения загрузки:
Допустим, у нас есть вариант использования загрузки нескольких файлов на сервер через http. Конечно, мы будем использовать наш модуль requests
для загрузки файлов за нас. Мы также будем использовать ThreadPoolExecutor
для имитации параллелизма.
Синтаксис:
Это синтаксис для инициализации tqdm
и атрибутов, которые можно установить.
def __init__(self, iterable=None, desc=None, total=None, leave=True, file=None, ncols=None, mininterval=0.1, maxinterval=10.0, miniters=None, ascii=None, disable=False, unit='it', unit_scale=False, dynamic_ncols=False, smoothing=0.3, bar_format=None, initial=0, position=None, postfix=None, unit_divisor=1000, write_bytes=None, lock_args=None, nrows=None, colour=None, delay=0, gui=False, **kwargs): """ Parameters ---------- iterable : iterable, optional Iterable to decorate with a progressbar. Leave blank to manually manage the updates. desc : str, optional Prefix for the progressbar. total : int or float, optional The number of expected iterations. If unspecified, len(iterable) is used if possible. If float("inf") or as a last resort, only basic progress statistics are displayed (no ETA, no progressbar). If `gui` is True and this parameter needs subsequent updating, specify an initial arbitrary large positive number, e.g. 9e9. leave : bool, optional If [default: True], keeps all traces of the progressbar upon termination of iteration. If `None`, will leave only if `position` is `0`. file : `io.TextIOWrapper` or `io.StringIO`, optional Specifies where to output the progress messages (default: sys.stderr). Uses `file.write(str)` and `file.flush()` methods. For encoding, see `write_bytes`. ncols : int, optional The width of the entire output message. If specified, dynamically resizes the progressbar to stay within this bound. If unspecified, attempts to use environment width. The fallback is a meter width of 10 and no limit for the counter and statistics. If 0, will not print any meter (only stats). mininterval : float, optional Minimum progress display update interval [default: 0.1] seconds. maxinterval : float, optional Maximum progress display update interval [default: 10] seconds. Automatically adjusts `miniters` to correspond to `mininterval` after long display update lag. Only works if `dynamic_miniters` or monitor thread is enabled. miniters : int or float, optional Minimum progress display update interval, in iterations. If 0 and `dynamic_miniters`, will automatically adjust to equal `mininterval` (more CPU efficient, good for tight loops). If > 0, will skip display of specified number of iterations. Tweak this and `mininterval` to get very efficient loops. If your progress is erratic with both fast and slow iterations (network, skipping items, etc) you should set miniters=1. ascii : bool or str, optional If unspecified or False, use unicode (smooth blocks) to fill the meter. The fallback is to use ASCII characters " 123456789#". disable : bool, optional Whether to disable the entire progressbar wrapper [default: False]. If set to None, disable on non-TTY. unit : str, optional String that will be used to define the unit of each iteration [default: it]. unit_scale : bool or int or float, optional If 1 or True, the number of iterations will be reduced/scaled automatically and a metric prefix following the International System of Units standard will be added (kilo, mega, etc.) [default: False]. If any other non-zero number, will scale `total` and `n`. dynamic_ncols : bool, optional If set, constantly alters `ncols` and `nrows` to the environment (allowing for window resizes) [default: False]. smoothing : float, optional Exponential moving average smoothing factor for speed estimates (ignored in GUI mode). Ranges from 0 (average speed) to 1 (current/instantaneous speed) [default: 0.3]. bar_format : str, optional Specify a custom bar string formatting. May impact performance. [default: '{l_bar}{bar}{r_bar}'], where l_bar='{desc}: {percentage:3.0f}%|' and r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, ' '{rate_fmt}{postfix}]' Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt, percentage, elapsed, elapsed_s, ncols, nrows, desc, unit, rate, rate_fmt, rate_noinv, rate_noinv_fmt, rate_inv, rate_inv_fmt, postfix, unit_divisor, remaining, remaining_s, eta. Note that a trailing ": " is automatically removed after {desc} if the latter is empty. initial : int or float, optional The initial counter value. Useful when restarting a progress bar [default: 0]. If using float, consider specifying `{n:.3f}` or similar in `bar_format`, or specifying `unit_scale`. position : int, optional Specify the line offset to print this bar (starting from 0) Automatic if unspecified. Useful to manage multiple bars at once (eg, from threads). postfix : dict or *, optional Specify additional stats to display at the end of the bar. Calls `set_postfix(**postfix)` if possible (dict). unit_divisor : float, optional [default: 1000], ignored unless `unit_scale` is True. write_bytes : bool, optional If (default: None) and `file` is unspecified, bytes will be written in Python 2. If `True` will also write bytes. In all other cases will default to unicode. lock_args : tuple, optional Passed to `refresh` for intermediate output (initialisation, iterating, and updating). nrows : int, optional The screen height. If specified, hides nested bars outside this bound. If unspecified, attempts to use environment height. The fallback is 20. colour : str, optional Bar colour (e.g. 'green', '#00ff00'). delay : float, optional Don't display until [default: 0] seconds have elapsed. gui : bool, optional WARNING: internal parameter - do not use. Use tqdm.gui.tqdm(...) instead. If set, will attempt to use matplotlib animations for a graphical output [default: False]. Returns ------- out : decorated iterator.
Код:
import requests from tqdm import tqdm from concurrent.futures import ThreadPoolExecutor from concurrent.futures import as_completed import os, time def upload(): """ A function to upload to a http server using requests url: https://httpbin.org/post -- A test url """ file_path = '/home/<your>/<path>/' # list all the files from a given path files_to_upload = os.listdir(file_path) # tqdm is used as a context manager with tqdm(total=len(files_to_upload), desc="Uploading", initial=0, unit_scale=True, colour='green') as pbar: with ThreadPoolExecutor(max_workers=20) as executor: for file_name in files_to_upload: with open(os.path.join(file_path, file_name), 'rb') as f: files = {'file': (file_name, f.read())} futures = executor.submit(requests.post, url='https://httpbin.org/post', files=files) if as_completed(futures): pbar.update(1) time.sleep(0.02) return "complete" upload()
Индикатор выполнения выглядит примерно так, как показано ниже. Конечно, вы можете выбрать интересующий вас цвет, чтобы заполнить полосу. Я выбрал зеленый, так как он дает пользователю ощущение удовлетворения, когда полоса заполняется. 😉
Теперь, когда у нас есть индикатор выполнения, работающий для загрузок, нам нужно реализовать его и для загрузок. Однако на этот раз мы будем использовать wrapattr
.
Использование tqdm wrapattr для отображения индикатора загрузки:
Синтаксис и использование:
@classmethod @contextmanager def wrapattr(cls, stream, method, total=None, bytes=True, **tqdm_kwargs): """ stream : file-like object. method : str, "read" or "write". The result of `read()` and the first argument of `write()` should have a `len()`. >>> with tqdm.wrapattr(file_obj, "read", total=file_obj.size) as fobj: ... while True: ... chunk = fobj.read(chunk_size) ... if not chunk: ... break """
Теперь мы будем использовать wrapattr
для отображения индикатора загрузки файлов с помощью requests
.
import requests from tqdm import tqdm from concurrent.futures import ThreadPoolExecutor import os, time import shutil def initiate_download(self): download_path = "<your download path>" # list of urls to download url_lst = "<your list of urls to download>" # use threads to download multiple files for concurrency with ThreadPoolExecutor(max_workers=20) as executor: result_lst = list() for url in url_lst: future = executor.submit(download, url) result_lst.append(future) for res in result_lst: # do something with your result pass def download(): response = requests.get(url='<your http url>', stream=True) file_size = int(zip_resp.headers.get('content-length')) with open("<your file path on your system>", "wb") as f: with tqdm.wrapattr(response.raw, "read", total=file_size, desc="Downloading", colour='green') as r_raw: shutil.copyfileobj(r_raw, f) return "Success" initiate_download()
Что мне лично нравится в wrapattr
, так это то, что вы можете использовать его для чтения или записи атрибута, а tqdm
позаботится обо всем. Вам не нужно ни вручную обновлять индикатор выполнения, ни беспокоиться о content-length.
В отличие от подхода, который мы обсуждали для загрузки, это намного проще, поскольку позволяет избежать хлопот, связанных с ручным обновлением индикатора выполнения.
Я обсудил 2 разных способа обновления индикатора выполнения с помощью tqdm
.
wrapattr
очень полезен, если вы используете shutil
для записи файлов в файловую систему, как мы будем писать в raw format
.
Резюме:
tqdm
— отличная библиотека для отображения индикаторов выполнения ваших загрузок и загрузок.- Он отлично работает с модулем
requests
. tqdm
поддерживает различные цвета. Пожалуйста, ознакомьтесь с их документацией, чтобы узнать о них.- Поддерживает контекстный менеджер, что весьма полезно.
wrapattr
автоматически выполняет обратный вызов обновления. Хорошо работает сshutil
Использованная литература:
- https://tqdm.github.io/
- https://stackoverflow.com/questions/15644964/python-progress-bar-and-downloads
Первоначально опубликовано на https://dock2learn.com.
Дополнительные материалы на plainenglish.io