Viviamo in un mondo di big data. Spesso i Big Data sono organizzati come un’ampia raccolta di piccoli set di dati (ovvero un grande set di dati composto da più file). Ottenere questi dati è spesso frustrante a causa del download (o dell’onere di acquisizione). Fortunatamente, con un po’ di codice, ci sono modi per automatizzare e velocizzare il download e l’acquisizione dei file.
L’automazione dei download dei file può far risparmiare molto tempo. Esistono diversi modi per automatizzare i download di file con Python. Il modo più semplice per scaricare file è utilizzare un semplice ciclo Python per scorrere un elenco di URL da scaricare. Questo approccio seriale può funzionare bene con pochi file di piccole dimensioni, ma se stai scaricando molti file o file di grandi dimensioni, ti consigliamo di utilizzare un approccio parallelo per massimizzare le tue risorse di calcolo.
Con una routine di download di file parallelo, puoi utilizzare meglio le risorse del tuo computer per scaricare più file contemporaneamente, risparmiando tempo. Questo tutorial dimostra come sviluppare una funzione di download di file generica in Python e applicarla per scaricare più file con approcci seriali e paralleli. Il codice in questo tutorial utilizza solo i moduli disponibili nella libreria standard Python, quindi non sono richieste installazioni.
Per questo esempio, abbiamo solo bisogno di requests
E multiprocessing
Moduli Python per scaricare file in parallelo. IL requests
E multiprocessing
i moduli sono entrambi disponibili nella libreria standard Python, quindi non sarà necessario eseguire alcuna installazione.
Importeremo anche il file time
modulo per tenere traccia del tempo necessario per scaricare singoli file e confrontare le prestazioni tra le routine di download seriale e parallela. IL time
module fa anche parte della libreria standard Python.
import requests import time from multiprocessing import cpu_count from multiprocessing.pool import ThreadPool
Dimostrerò i download di file paralleli in Python utilizzando grigliaMET File NetCDF che contengono dati sulle precipitazioni giornaliere per gli Stati Uniti.
Qui specifico gli URL di quattro file in un elenco. In altre applicazioni è possibile generare a livello di codice un elenco di file da scaricare.
urls = ('https://www.northwestknowledge.net/metdata/data/pr_1979.nc', 'https://www.northwestknowledge.net/metdata/data/pr_1980.nc', 'https://www.northwestknowledge.net/metdata/data/pr_1981.nc', 'https://www.northwestknowledge.net/metdata/data/pr_1982.nc')
Ogni URL deve essere associato al percorso di download. Qui sto scaricando i file nella directory “Download” di Windows. Ho codificato i nomi dei file in un elenco per semplicità e trasparenza. Data la tua applicazione, potresti voler scrivere codice che analizzerà l’URL di input e lo scaricherà in una directory specifica.
fns = (r'C:\Users\konrad\Downloads\pr_1979.nc', r'C:\Users\konrad\Downloads\pr_1980.nc', r'C:\Users\konrad\Downloads\pr_1981.nc', r'C:\Users\konrad\Downloads\pr_1982.nc')
Il multiprocessing richiede che le funzioni parallele abbiano un solo argomento (ci sono alcune soluzioni alternative, ma non ne parleremo qui). Per scaricare un file dovremo passare due argomenti, un URL e un nome file. Quindi comprimeremo il file urls
E fns
elenchi insieme per ottenere un elenco di tuple. Ogni tupla nell’elenco conterrà due elementi; un URL e il nome del file di download per l’URL. In questo modo possiamo passare un singolo argomento (la tupla) che contiene due informazioni.
inputs = zip(urls, fns)
Ora che abbiamo specificato gli URL da scaricare e i nomi dei file associati, abbiamo bisogno di una funzione per scaricare gli URL ( download_url
).
Passeremo un argomento ( arg
) A download_url
. Questo argomento sarà un iterabile (elenco o tupla) in cui il primo elemento è l’URL da scaricare ( url
) e il secondo elemento è il nome del file ( fn
). Gli elementi sono assegnati a variabili ( url
E fn
) per la leggibilità.
Ora crea un’istruzione try in cui l’URL viene recuperato e scritto nel file dopo che è stato creato. Quando il file viene scritto, vengono restituiti l’URL e l’ora del download. Se si verifica un’eccezione, viene stampato un messaggio.
IL download_url
la funzione è la carne del nostro codice. Fa il lavoro vero e proprio di download e creazione di file. Ora possiamo utilizzare questa funzione per scaricare file in seriale (usando un loop) e in parallelo. Esaminiamo questi esempi.
def download_url(args):
t0 = time.time()
url, fn = args(0), args(1)
try:
r = requests.get(url)
with open(fn, 'wb') as f:
f.write(r.content)
return(url, time.time() - t0)
except Exception as e:
print('Exception in download_url():', e)
Per scaricare l’elenco degli URL nei file associati, eseguire il ciclo dell’iterabile ( inputs
) che abbiamo creato, passando ogni elemento a download_url
. Al termine di ogni download, stamperemo l’URL scaricato e il tempo impiegato per il download.
Il tempo totale per scaricare tutti gli URL verrà stampato al termine di tutti i download.
t0 = time.time()
for i in inputs:
result = download_url(i)
print('url:', result(0), 'time:', result(1))
print('Total time:', time.time() - t0)
Produzione:
url: https://www.northwestknowledge.net/metdata/data/pr_1979.nc time: 16.381176710128784
url: https://www.northwestknowledge.net/metdata/data/pr_1980.nc time: 11.475878953933716
url: https://www.northwestknowledge.net/metdata/data/pr_1981.nc time: 13.059367179870605
url: https://www.northwestknowledge.net/metdata/data/pr_1982.nc time: 12.232381582260132
Total time: 53.15849542617798
Per scaricare i singoli file sono stati necessari dagli 11 ai 16 secondi. Il tempo di download totale è stato poco meno di un minuto. I tempi di download varieranno in base alla connessione di rete specifica.
Confrontiamo questo approccio seriale (loop) con l’approccio parallelo riportato di seguito.
Per iniziare, crea una funzione ( download_parallel
) per gestire il download parallelo. La funzione ( download_parallel
) prenderà un argomento, un iterabile contenente URL e nomi di file associati (the inputs
variabile che abbiamo creato in precedenza).
Successivamente, ottieni il numero di CPU disponibili per l’elaborazione. Ciò determinerà il numero di thread da eseguire in parallelo.
Ora usa il multiprocessing
ThreadPool
per mappare il inputs
al download_url
funzione. Qui usiamo il imap_unordered
metodo di ThreadPool
e passalo il download_url
funzione e argomenti di input a download_url
(IL inputs
variabile). IL imap_unordered
il metodo verrà eseguito download_url
contemporaneamente per il numero di thread specificati (ovvero download parallelo).
Pertanto, se abbiamo quattro file e quattro thread, tutti i file possono essere scaricati contemporaneamente invece di attendere il completamento di un download prima dell’avvio del successivo. Ciò può far risparmiare una notevole quantità di tempo di elaborazione.
Nella parte finale del download_parallel
vengono stampati gli URL scaricati e il tempo necessario per scaricare ciascun URL.
def download_parallel(args):
cpus = cpu_count()
results = ThreadPool(cpus - 1).imap_unordered(download_url, args)
for result in results:
print('url:', result(0), 'time (s):', result(1))
Una volta che inputs
E download_parallel
sono definiti, i file possono essere scaricati in parallelo con una singola riga di codice.
download_parallel(inputs)
Produzione:
url: https://www.northwestknowledge.net/metdata/data/pr_1980.nc time (s): 14.641696214675903
url: https://www.northwestknowledge.net/metdata/data/pr_1981.nc time (s): 14.789752960205078
url: https://www.northwestknowledge.net/metdata/data/pr_1979.nc time (s): 15.052601337432861
url: https://www.northwestknowledge.net/metdata/data/pr_1982.nc time (s): 23.287317752838135
Total time: 23.32273244857788
Si noti che è stato necessario più tempo per scaricare ogni singolo file con questo approccio. Ciò potrebbe essere il risultato di una modifica della velocità della rete o del sovraccarico necessario per mappare i download sui rispettivi thread. Anche se il download dei singoli file ha richiesto più tempo, il metodo parallelo ha comportato una riduzione del 50% del tempo di download totale.
Puoi vedere come l’elaborazione parallela può ridurre notevolmente il tempo di elaborazione per più file. All’aumentare del numero di file, risparmierai molto più tempo utilizzando un approccio di download parallelo.
Automatizzare i download dei file nelle routine di sviluppo e analisi può farti risparmiare molto tempo. Come dimostrato da questo tutorial, l’implementazione di una routine di download parallelo può ridurre notevolmente il tempo di acquisizione dei file se sono necessari molti file o file di grandi dimensioni.