Как написать индикатор прогресса загрузки на Python?

Пишу небольшое приложение для загрузки файлов по http (как, например, описанное здесь).

Я также хочу включить небольшой индикатор прогресса загрузки, показывающий процент процесса загрузки.

Вот что я придумал:

    sys.stdout.write(rem_file + "...")    
    urllib.urlretrieve(rem_file, loc_file, reporthook=dlProgress)

    def dlProgress(count, blockSize, totalSize):
      percent = int(count*blockSize*100/totalSize)
      sys.stdout.write("%2d%%" % percent)
      sys.stdout.write("\b\b\b")
      sys.stdout.flush()

Вывод: MyFileName ... 9%

Есть ли другие идеи или рекомендации по этому поводу?

Одна вещь, которая несколько раздражает, - это мигающий курсор в терминале на первой цифре процента. Есть ли способ предотвратить это? Есть ли способ скрыть курсор?

Обновлено:

Вот лучшая альтернатива с использованием глобальной переменной для имени файла в dlProgress и кода '\ r':

    global rem_file # global variable to be used in dlProgress

    urllib.urlretrieve(rem_file, loc_file, reporthook=dlProgress)

    def dlProgress(count, blockSize, totalSize):
      percent = int(count*blockSize*100/totalSize)
      sys.stdout.write("\r" + rem_file + "...%d%%" % percent)
      sys.stdout.flush()

Вывод: MyFileName ... 9%

И курсор появляется в КОНЦЕ строки. Намного лучше.

global rem_file имеет смысл только внутри функции, где вы привязываете его к новому объекту rem_file = ..., в противном случае (если вы только читаете его значение) global rem_file не нужен.

jfs 14.12.2008 16:04

Вы также можете сделать / r + flush () на стандартном выходе. Я просто предполагаю, что это работает в Windows на основе упомянутого вами поведения терминала.

meawoppl 03.05.2014 00:53

связанные stackoverflow.com/questions/15644964/…

matt wilkie 22.03.2015 09:35
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
56
3
30 620
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Если вы используете пакет curses, у вас будет гораздо больший контроль над консолью. Это также связано с более высокими затратами на сложность кода и, вероятно, не требуется, если вы не разрабатываете большое консольное приложение.

В качестве простого решения вы всегда можете поместить вращающееся колесо в конец сообщения о состоянии (последовательность символов |, \, -, /, которая действительно хорошо выглядит под мигающим курсором.

Вы также можете попробовать:

sys.stdout.write("\r%2d%%" % percent)
sys.stdout.flush()

Использование одного возврата каретки в начале строки, а не нескольких пробелов. Ваш курсор по-прежнему будет мигать, но он будет мигать после знака процента, а не под первой цифрой, и с одним управляющим символом вместо трех вы можете получить меньше мерцания.

Ответ принят как подходящий

В http://pypi.python.org/pypi/progressbar/2.2 есть библиотека текстовых индикаторов выполнения для python, которая может оказаться вам полезной:

This library provides a text mode progressbar. This is tipically used to display the progress of a long running operation, providing a visual clue that processing is underway.

The ProgressBar class manages the progress, and the format of the line is given by a number of widgets. A widget is an object that may display diferently depending on the state of the progress. There are three types of widget: - a string, which always shows itself; - a ProgressBarWidget, which may return a diferent value every time it's update method is called; and - a ProgressBarWidgetHFill, which is like ProgressBarWidget, except it expands to fill the remaining width of the line.

The progressbar module is very easy to use, yet very powerful. And automatically supports features like auto-resizing when available.

как иметь несколько индикаторов выполнения в терминале, если несколько загрузок указаны в отдельных потоках?

Ciasto piekarz 05.07.2014 10:34

Для небольших файлов вам могут понадобиться следующие строки, чтобы избежать сумасшедших процентов:

sys.stdout.write ("\ r% 2d %%"% процентов)

sys.stdout.flush ()

Ваше здоровье

Вот как я это сделал, это может вам помочь: https://github.com/mouuff/MouDownloader/blob/master/api/download.py

Я использовал этот код:

url = (<file location>)
file_name = url.split('/')[-1]
u = urllib2.urlopen(url)
f = open(file_name, 'wb')
meta = u.info()
file_size = int(meta.getheaders("Content-Length")[0])
print "Downloading: %s Bytes: %s" % (file_name, file_size)

file_size_dl = 0
block_sz = 8192
while True:
    buffer = u.read(block_sz)
    if not buffer:
        break

    file_size_dl += len(buffer)
    f.write(buffer)
    status = r"%10d [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size)
    status = status + chr(8)*(len(status)+1)
    print status,

f.close()

Поздно на вечеринку, как обычно. Вот реализация, которая поддерживает отчеты о прогрессе, например, ядро ​​urlretrieve:

import urllib2

def urlretrieve(urllib2_request, filepath, reporthook=None, chunk_size=4096):
    req = urllib2.urlopen(urllib2_request)

    if reporthook:
        # ensure progress method is callable
        if hasattr(reporthook, '__call__'):
            reporthook = None

        try:
            # get response length
            total_size = req.info().getheaders('Content-Length')[0]
        except KeyError:
            reporthook = None

    data = ''
    num_blocks = 0

    with open(filepath, 'w') as f:
        while True:
            data = req.read(chunk_size)
            num_blocks += 1
            if reporthook:
                # report progress
                reporthook(num_blocks, chunk_size, total_size)
            if not data:
                break
            f.write(data)

    # return downloaded length
    return len(data)

Как бы то ни было, вот код, который я использовал, чтобы заставить его работать:

from urllib import urlretrieve
from progressbar import ProgressBar, Percentage, Bar

url = "http://......."
fileName = "file"
pbar = ProgressBar(widgets=[Percentage(), Bar()])
urlretrieve(url, fileName, reporthook=dlProgress)

def dlProgress(count, blockSize, totalSize):
    pbar.update( int(count * blockSize * 100 / totalSize) )

Это дает мне только: pbar.update (int (count * blockize * 100 / totalSize)) NameError: глобальное имя 'blockize' не определено

rm- 14.10.2016 11:19

это была опечатка. Это должен был быть входной параметр. Я обновил ответ, чтобы отразить это. Спасибо!

tstone2077 17.10.2016 16:35

def download_progress_hook(count, blockSize, totalSize):
  """A hook to report the progress of a download. This is mostly intended for users with slow internet connections. Reports every 5% change in download progress.
  """
  global last_percent_reported
  percent = int(count * blockSize * 100 / totalSize)

  if last_percent_reported != percent:
    if percent % 5 == 0:
      sys.stdout.write("%s%%" % percent)
      sys.stdout.flush()
    else:
      sys.stdout.write(".")
      sys.stdout.flush()

    last_percent_reported = percent

urlretrieve(url, filename, reporthook=download_progress_hook)

Другие вопросы по теме