He aquí una versión que se descarga el archivo en un bytearray
en un hilo separado.
Como se ha mencionado en otras respuestas y comentarios, hay otros alternativs que se desarrollan con las operaciones asincrónicas en mente, así que no leer demasiado en la decisión de ir con threading
es solo para demostrar el concepto (y debido a la comodidad, ya que viene con python).
En el siguiente código, si el tamaño del archivo es conocido, cada .
le corresponde al 1%. Como un bono, la descarga y el número total de bytes que serán impresos en el inicio de la línea como (1234 B / 1234567 B)
. Si el tamaño no es conocido, la solución alternativa es que cada una de .
representan una porción.
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()
Tenga en cuenta que me he dejado la cerradura para proteger contra el acceso simultáneo a stdout
para reducir el ruido. También he dejado fuera de la escritura de la bytarray
para presentar al final (o de la escritura de los fragmentos de archivo a medida que se reciben si el archivo es grande), pero tenga en cuenta que puede que desee utilizar un bloqueo para que así si puedes leer y/o escribir en el mismo archivo en cualquier otra parte de su secuencia de comandos.