2011-12-26 15 views
22

Desidero scaricare alcune pagine da un sito Web e l'ho fatto con successo utilizzando curl ma mi chiedevo se in qualche modo lo curl scarica più pagine alla volta, proprio come fa la maggior parte dei download manager, sarà accelera un po 'le cose. È possibile farlo nel programma di utilità della riga di comando curl?Download parallelo utilizzando l'utilità della riga di comando di Curl

Il comando corrente che sto usando è

curl 'http://www...../?page=[1-10]' 2>&1 > 1.html 

Qui sto scaricando le pagine da 1 a 10 e la loro memorizzazione in un file chiamato 1.html.

Inoltre, è possibile per curl a scrivere l'output di ogni URL di file separato dire URL.html, dove URL è l'URL reale della pagina sotto processo.

+0

pre-richiesta per scoprire la lunghezza del contenuto, utilizzare '--range' per unire il singolo a più download, eseguire il curl multiprocesso, mantenere l'ordine dei blocchi e unirli non appena è stata ordinata la sequenza , è ciò che la maggior parte degli sviluppatori sta facendo (ad esempio: [progetto htcat] (https://github.com/eladkarako/htcat)) –

risposta

22

Bene, curl è solo un semplice processo UNIX. È possibile avere il numero di questi processi curl in esecuzione in parallelo e l'invio delle loro uscite a file diversi.

curl può utilizzare la parte nome file dell'URL per generare il file locale. Basta usare l'opzione -O (man curl per i dettagli).

Si potrebbe usare qualcosa come il seguente

urls="http://example.com/?page1.html http://example.com?page2.html" # add more URLs here 

for url in $urls; do 
    # run the curl job in the background so we can start another job 
    # and disable the progress bar (-s) 
    echo "fetching $url" 
    curl $url -O -s & 
done 
wait #wait for all background jobs to terminate 
+3

diciamo che devo scaricare 100 pagine ... lo script avvierà 100 istanze di arricciatura contemporaneamente (potrebbe soffocare la rete) ... possiamo fare qualcosa come in un dato momento, solo le istanze X di 'curl' sono in esecuzione e non appena uno di loro finisce il suo lavoro, lo script lancia un'altra istanza ... alcuni sorta di 'Job Scheduling' ?? –

+0

+1 per la risposta comunque. –

+0

Ravi ... questo diventa più difficile. È necessaria una coda di lavoro offerta da più processi. Una soluzione semplice sarebbe quella di inviare tutti i lavori al comando 'batch' di UNIX (prova' man batch'). Esegue i lavori quando il carico del sistema è inferiore a una determinata soglia. Quindi molti lavori verrebbero messi in coda e solo pochi funzioneranno alla volta. – nimrodm

0

Non sono sicuro di arricciare, ma è possibile farlo utilizzando wget.

wget \ 
    --recursive \ 
    --no-clobber \ 
    --page-requisites \ 
    --html-extension \ 
    --convert-links \ 
    --restrict-file-names=windows \ 
    --domains website.org \ 
    --no-parent \ 
     www.website.org/tutorials/html/ 
4

Curl può anche accelerare il download di un file da dividere in parti:

$ man curl |grep -A2 '\--range' 
     -r/--range <range> 
       (HTTP/FTP/SFTP/FILE) Retrieve a byte range (i.e a partial docu- 
       ment) from a HTTP/1.1, FTP or SFTP server or a local FILE. 

Ecco uno script che lancerà automaticamente ricciolo con il numero desiderato di processi simultanei: https://github.com/axelabs/splitcurl

2

Per l'avvio di comandi paralleli, perché non utilizzare il venerabile make c utility di riga di comando .. Supporta l'esecuzione parallell e il tracciamento delle dipendenze e quant'altro.

Come? Nella directory in cui si sta scaricando i file, creare un nuovo file chiamato Makefile con il seguente contenuto:

# which page numbers to fetch 
numbers := $(shell seq 1 10) 

# default target which depends on files 1.html .. 10.html 
# (patsubst replaces % with %.html for each number) 
all: $(patsubst %,%.html,$(numbers)) 

# the rule which tells how to generate a %.html dependency 
# [email protected] is the target filename e.g. 1.html 
%.html: 
     curl -C - 'http://www...../?page='$(patsubst %.html,%,[email protected]) -o [email protected] 
     mv [email protected] [email protected] 

NOTA Le ultime due righe dovrebbero iniziare con un carattere di tabulazione (invece di 8 spazi) o fare testamento non accettare il file.

Ora basta eseguire:

make -k -j 5 

Il comando ricciolo ho usato memorizza l'output in 1.html.tmp e solo se il comando ricciolo riesce poi sarà rinominato 1.html (dal comando mv sulla riga successiva). Pertanto, se alcuni download non riescono, è possibile eseguire nuovamente lo stesso comando make e riprendere/riprovare a scaricare i file che non sono riusciti a scaricare durante la prima volta. Una volta che tutti i file sono stati scaricati correttamente, make segnalerà che non c'è più nulla da fare, quindi non c'è nulla di male nel farli funzionare un altro tempo per essere "sicuri".

(L'interruttore -k dice fare per mantenere scaricando il resto dei file, anche se un singolo download dovrebbe fallire.)

+0

"-j 5" dice di far funzionare al massimo 5 comandi di arricciatura in parallelo. –

+0

Davvero la soluzione migliore dal momento che consente di riprendere i download non riusciti e usa 'make' che è sia robusto che disponibile su qualsiasi sistema Unix. – nimrodm

31

La mia risposta è un po 'tardi, ma credo che tutte le risposte esistenti cadono solo un po' corto. Il modo in cui faccio cose del genere è con xargs, che è in grado di eseguire un numero specificato di comandi nei sottoprocessi.

L'one-liner che userei è, semplicemente:

$ seq 1 10 | xargs -n1 -P2 bash -c 'i=$0; url="http://example.com/?page${i}.html"; curl -O -s $url' 

Questo garantisce che qualche spiegazione. L'utilizzo di -n 1 indica a xargs di elaborare un singolo argomento di input alla volta. In questo esempio, i numeri 1 ... 10 vengono elaborati separatamente. E -P 2 dice a xargs di mantenere 2 processi secondari in esecuzione tutto il tempo, ognuno dei quali gestisce un singolo argomento, fino a quando tutti gli argomenti di input sono stati elaborati.

Si può pensare a questo come MapReduce nella shell. O forse solo la fase Map. Indipendentemente da ciò, è un modo efficace per fare un sacco di lavoro mentre si assicura di non bombardare la macchina. È possibile fare qualcosa di simile in un ciclo for in una shell, ma finire con la gestione dei processi, che inizia a sembrare inutile una volta che ti rendi conto di quanto follemente sia questo uso di xargs.

Aggiornamento: Sospetto che il mio esempio con xargs possa essere migliorato (almeno su Mac OS X e BSD con il flag -J). Con GNU Parallelamente, il comando è un po 'meno ingombrante così:

parallel --jobs 2 curl -O -s http://example.com/?page{}.html ::: {1..10} 
+3

Si noti inoltre che se si dispone di una versione completa di xargs, è sufficiente effettuare le seguenti operazioni: 'seq 1 10 | xargs -I {} -P2 - curl -O -s 'http://example.com/?page {} .html'' – Six

2

Eseguire un numero limitato di processo è facile se il vostro sistema ha comandi come pidof o pgrep che, dato un nome di processo, restituire i PID (il il conteggio dei pid indica quanti sono in esecuzione).

Qualcosa di simile a questo:

#!/bin/sh 
max=4 
running_curl() { 
    set -- $(pidof curl) 
    echo $# 
} 
while [ $# -gt 0 ]; do 
    while [ $(running_curl) -ge $max ] ; do 
     sleep 1 
    done 
    curl "$1" --create-dirs -o "${1##*://}" & 
    shift 
done 

per chiamare in questo modo:

script.sh $(for i in `seq 1 10`; do printf "http://example/%s.html " "$i"; done) 

La linea ricciolo dello script è testato.

Problemi correlati