Pobieranie plików około 10gb za pomocą http

0

Potrzebuję pobierać pliki około 10gb każdy, następnie sprawdzać czy pobrały się poprawnie.
Za pomocą biblioteki requests nie działa to zawsze (w zależności od łącza działa albo nie działa)
Przykład z użyciem requests:

                r = requests.get(url, stream=True)
                print(url)
                with open(save_product_name, 'wb') as fd:
                    for chunk in r.iter_content(chunk_size=512):
                        fd.write(chunk)

Szukając rozwiązania natknąłem się na post:
https://github.com/aio-libs/aiohttp/issues/2249#issuecomment-327896106

Zgodnie z zasadą copy-pasty-programmingu poczyniłem odpowiednie zmiany:

import asyncio
import sys
from time import time

import aiohttp


async def async_download(file_url: str):
    total_size = 0
    start = time()
    print("start download " + file_url)
    file = open("test.zip", 'wb')
    async with aiohttp.ClientSession() as session:
        async with session.get(file_url, timeout=None) as r:
            while True:
                chunk = await r.content.read(16144)
                if not chunk:
                    break
                total_size += len(chunk)
                file.write(chunk)
                message = f'{time() - start:0.2f}s, downloaded: {total_size / (1024 * 1024):0.0f}MB'
                sys.stdout.write('\r' + message)
    file.close()
    sys.stdout.flush()

url = "http://speedtest.tele2.net/10GB.zip"
loop = asyncio.get_event_loop()
loop.run_until_complete(async_download(file_url=url))

Po uruchomieniu z innymi plikami (do których dostęp jest już za pomocą generowatnego tokena)
otrzymuję błąd:

Traceback (most recent call last):
  File "C:\Users\Admin\Desktop\fsadas\test.py", line 28, in <module>
    loop.run_until_complete(async_download(file_url=url))
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38-32\lib\asyncio\base_events.py", line 616, in run_until_complete
    return future.result()
  File "C:\Users\Admin\Desktop\fsadas\test.py", line 16, in async_download
    chunk = await r.content.read(16144)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38-32\lib\site-packages\aiohttp\streams.py", line 368, in read
    await self._wait('read')
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38-32\lib\site-packages\aiohttp\streams.py", line 296, in _wait
    await waiter
aiohttp.client_exceptions.ClientPayloadError: Response payload is not completed

Moje pytania:

  1. Jak pobierać tak duże pliki?
  2. W jaki sposób napisać tą funkcję tak, aby można było otworzyć około 20 sesji pobierania jednocześnie, każdy w innym wątku (może lepiej subprocess)?
  3. W jaki sposób sprawdzać czy plik pobrał się poprawnie?

Chciałbym napisać testy do tej funkcji - będę wdzięczny za podpowiedzi

0

Jaki jest sens otwierania kilku sesji naraz i tym samym uruchamianie kilku transferów naraz? To nie przyspieszy pobierania, bo łącze po jednej lub drugiej stronie będzie wykorzystane do granic możliwości (po tej stronie, po której jest wolniejsze) przy pobieraniu jednego pliku. Lepiej już pobierać pliki pojedynczo, jeden za drugim.

Sprawdzanie pliku to po pierwsze uzyskanie informacji o wielkości pliku co do bajtu i po pobraniu sprawdzenie czy plik tyle ma. Natomiast poprawność treści sprawdzisz wykorzystując funkcje skrótu, np. MD5 lub SHA2. Na serwerze przelicz funkcję dla każdego pliku i udostępnij je. Po pobraniu pliku przelicz skrót po stronie klienta i porównaj go ze skrótem udostępnionym przez serwer. jeżeli skrót będzie taki sam, to z bardzo dużym prawdopodobieństwem plik jest pobrany poprawnie (jest identyczny po obu stronach).

0

Dodałem taką procedurę:

def d_download(url, path = "test1111111.zip"):
    r = requests.get(url, stream=True)
    chunk_size = 2 ** 20  # download in 1 MB chunks
    mode = "ab"
    with open(path, mode) as f:
        for chunk in r.iter_content(chunk_size=chunk_size):
            if chunk:  # filter out keep-alive new chunks
                f.write(chunk)

Działa
byłbym wdzięczny za podpowiedź jak napisać testy i zrobić asercje
Kodu nie przetestować w pełni więc będę wdzięczny za inne propozycje

0

Ustaw sobie jakiś czas, po którym zrobic restart jeśli request sfailuje; zapuść to i niech ssie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1