Pergunta

Estou escrevendo um pequeno aplicativo para baixar arquivos via http (como, por exemplo, descrito aqui).

Também quero incluir um pequeno indicador de progresso do download mostrando a porcentagem do progresso do download.

Aqui está o que eu descobri:

    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()

Saída:MeuNomeArquivo...9%

Alguma outra idéia ou recomendação para fazer isso?

Uma coisa um tanto irritante é o cursor piscando no terminal no primeiro dígito da porcentagem.Há uma maneira de prevenir isto?Existe uma maneira de ocultar o cursor?

EDITAR:

Aqui está uma alternativa melhor usando uma variável global para o nome do arquivo em dlProgress e o código ' ':

    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()

Saída:MeuNomeArquivo...9%

E o cursor aparece no FIM da linha.Muito melhor.

Foi útil?

Solução

Há uma biblioteca de barra de progresso de texto para python em http://pypi.python.org/pypi/progressbar/2.2 que você pode achar útil:

Esta biblioteca fornece uma barra de progresso em modo texto.Normalmente é usado para exibir o progresso de uma operação de longa duração, fornecendo uma pista visual de que o processamento está em andamento.

A classe ProgressBar gerencia o progresso, e o formato da linha é fornecido por vários widgets.Um widget é um objeto que pode ser exibido de forma diferente dependendo do estado do progresso.Existem três tipos de widget:- uma string, que sempre se mostra;- um ProgressBarWidget, que pode retornar um valor diferente toda vez que seu método update for chamado;e - um ProgressBarWidgetHFill, que é como ProgressBarWidget, exceto que se expande para preencher a largura restante da linha.

O módulo progressbar é muito fácil de usar, mas muito poderoso.E suporta automaticamente recursos como redimensionamento automático, quando disponível.

Outras dicas

Você também pode tentar:

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

Usando um único retorno de carro no início da string, em vez de vários retrocessos.Seu cursor ainda piscará, mas piscará após o sinal de porcentagem, e não abaixo do primeiro dígito, e com um caractere de controle em vez de três, você poderá obter menos oscilação.

Para constar, aqui está o código que usei para fazê-lo funcionar:

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) )

Se você usar o curses pacote, você tem um controle muito maior do console.Ele também tem um custo mais alto em termos de complexidade de código e provavelmente é desnecessário, a menos que você esteja desenvolvendo um grande aplicativo baseado em console.

Para uma solução simples, você sempre pode colocar a roda giratória no final da mensagem de status (a sequência de caracteres |, \, -, / o que realmente parece bom sob o cursor piscando.

Eu usei este código:

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()
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)

Para arquivos pequenos, você pode precisar destas linhas para evitar porcentagens malucas:

sys.stdout.write(" %2d%%" % por cento)

sys.stdout.flush()

Saúde

Atrasado para a festa, como sempre.Aqui está uma implementação que suporta relatórios de progresso, como o núcleo 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)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top