Como imprimir "pontos" (ou outro tipo de retorno) durante a gravação de um arquivo em python?

0

Pergunta

Eu estou tentando imprimir um visível feedback para o usuário no terminal, enquanto o meu aplicação donwloads um arquivo da internet e gravá-lo para a unidade de disco rígido, mas eu não poderia encontrar como fazer isso lendo a documentação ou pesquisando-lo.

Este é o meu código:

res = requests.get(url_to_file)
with open("./downloads/%s" % (file_name), 'wb') as f:
    f.write(res.content)

Eu estava esperando para descobrir como fazer algo parecido com este:

Downloading file ........
 # it keeps going ultil the download is finished and the file writen
Done!

Eu sou realmente strugling para começar, porque nenhum dos métodos retorna uma "promessa" (como javascript).

Qualquer ajuda seria muito apreciado! Obrigado!

file promise python
2021-11-24 05:40:54
2

Melhor resposta

3

requests.get por padrão transfere a totalidade do pedido de recurso, antes de ele voltar para você. No entanto, ele tem um argumento opcional stream, que permite que você chamar .iter_content ou .iter_lines no Response objecto. Isso permite que você tome ação de todos os N bytes (ou como cada bloco de dados chegam), ou em cada linha, respectivamente. Algo como isto:

chunks = []
chunk_size = 16384     # 16Kb chunks
# alternately
# chunk_size = None    # whenever a chunk arrives
res = requests.get(url_to_file, stream=True)
for chunk in res.iter_content(chunk_size):
    chunks.append(chunk)
    print(".", end="")
data = b''.join(chunks)

Isso ainda blocos embora, então nada mais irá acontecer. Se você quer mais do JavaScript estilo, por Grismar comentário, você deve executar em Python assíncrono loop. Nesse caso, eu sugiro usar o aiohttp em vez de requests, como ele é criado com async estilo em mente.

2021-11-24 06:52:04

Muito obrigado por sua resposta! Foi muito rápido! haha eu fiz perceber e o conceito e é bom saber que existem assíncrono recursos em python. Por alguma razão, quando eu fechar a candidatura é composta pelo seu código, impresso somente os arquivos depois de o pedido ter terminado. Provavelmente eu estou faltando alguma coisa...
guilfer
1

Aqui está uma versão que vai baixar o arquivo em um bytearray em uma thread separada.

Como mencionado em outras respostas e comentários, há outros alternativs que são desenvolvidos com operações assíncronas em mente, então não leia muito para a decisão de ir com threading, é apenas para demonstrar o conceito (e, por conveniência, uma vez que ele vem com python).

No código abaixo, se o tamanho do arquivo é conhecido, cada . corresponderá a 1%. Como um bônus, o download e o número total de bytes que serão impressos no início da linha, como (1234 B / 1234567 B). Se tamanho não for conhecido, a solução alternativa é ter cada . representam um bloco.

import requests
import threading


def download_file(url: str):
    headers = {"<some_key>": "<some_value>"}
    data = bytearray()
    with requests.get(url, headers=headers, stream=True) as request:
        if file_size := request.headers.get("Content-Length"):
            file_size = int(file_size)
        else:
            file_size = None
        received = 0
        for chunk in request.iter_content(chunk_size=2**15):
            received += len(chunk)
            data += chunk
            try:
                num_dots = int(received * 100 / file_size)
                print(
                    f"({received} B/{file_size} B) "
                    + "." * num_dots, end="\r"
                )
            except TypeError:
                print(".", end="")
        print("\nDone!")

url = "<some_url>"
thread = threading.Thread(target=download_file, args=(url,))
thread.start()
# Do something in the meantime
thread.join()

Tenha em mente que deixei de fora o bloqueio para proteger contra o acesso simultâneo stdout para reduzir o ruído. Eu também deixou de fora a escrever a bytarray para arquivo no final (ou a escrita de blocos de arquivo como eles são recebidos se o arquivo for grande), mas tenha em mente que você pode querer usar um bloqueio para que bem se você ler e/ou escrever para o mesmo ficheiro em qualquer outra parte do seu script.

2021-11-24 05:57:53

É impressionante! Eu acho que entendo o conceito, mas eu sou bastante novo para python e resolvi fazer o caminho mais fácil haha eu sou marcar answaer e assim que eu aprender mais sobre threading eu com certeza vou revesit-lo! Muito obrigado!
guilfer

Em outros idiomas

Esta página está em outros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................