2011-12-26 17 views
22

Quiero descargar algunas páginas de un sitio web y lo hice con éxito usando curl pero me preguntaba si de alguna manera curl descarga varias páginas a la vez como lo hacen la mayoría de los administradores de descarga, lo hará acelerar las cosas un poco. ¿Es posible hacerlo en la utilidad de línea de comandos curl?Descarga paralela utilizando la utilidad de línea de comandos Curl

El comando actual que estoy usando es

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

Aquí estoy descargando páginas de 1 a 10 y los almacena en un archivo llamado 1.html.

Además, es posible que curl escriba la salida de cada URL en un archivo separado, por ejemplo URL.html, donde URL es la URL real de la página en proceso.

+0

pre-solicitud para conocer la longitud del contenido, use '-range' para empalmar las descargas individuales a múltiples, ejecute curl de procesos múltiples, mantenga el orden de los fragmentos y únase a ellos tan pronto como tenga una secuencia ordenada , es lo que la mayoría de los desarrolladores están haciendo (por ejemplo: [proyecto htcat] (https://github.com/eladkarako/htcat)) –

Respuesta

22

Bueno, curl es sólo un simple proceso de UNIX. Puede tener tantos de estos procesos curl ejecutándose en paralelo y enviando sus salidas a diferentes archivos.

curl puede usar el nombre de archivo parte de la URL para generar el archivo local. Simplemente use la opción -O (man curl para más detalles).

Usted podría utilizar algo como lo siguiente

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

Digamos que tengo que descargar 100 páginas ... tu script comenzará 100 instancias curl simultáneamente (Podría ahogar la red) ... podemos hacer algo como en un momento dado, solo se ejecutan X instancias de 'curl' y tan pronto como uno de ellos finalice su trabajo, el script iniciará otra instancia ... alguna tipo de 'Job Scheduling' ?? –

+0

+1 para la respuesta de todos modos. –

+0

Ravi ... esto se vuelve más difícil. Necesita una cola de trabajos atendida por múltiples procesos. Una solución simple sería enviar todos los trabajos al comando 'batch' de UNIX (pruebe' man batch'). Ejecuta trabajos cuando la carga del sistema está por debajo de un cierto umbral. Por lo tanto, la mayoría de los trabajos se pondrán en cola y solo unos pocos se ejecutarán a la vez. – nimrodm

0

No estoy seguro acerca de curl, pero puede hacerlo usando 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 también puede acelerar la descarga de un archivo mediante su división en partes:

$ 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. 

Aquí es un script que se iniciará automáticamente con el enrollamiento el número deseado de procesos concurrentes: https://github.com/axelabs/splitcurl

2

Para el lanzamiento de comandos paralelos, ¿por qué no utilizar el venerable make c Utilidad de línea ommand. Admite la ejecución en paralelo y el seguimiento de dependencias y otras cosas.

¿Cómo? En el directorio en el que está descargando los archivos, crear un nuevo archivo llamado Makefile con el siguiente contenido:

# 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 Las dos últimas líneas deben comenzar con un carácter de tabulación (en lugar de 8 espacios) o hacer la voluntad no acepta el archivo.

Ahora se acaba de ejecutar:

make -k -j 5 

El comando curl Solía ​​almacenará el resultado en 1.html.tmp y sólo si el comando curl tiene éxito, entonces será renombrado a 1.html (por el comando mv en la línea siguiente) Por lo tanto, si falla alguna descarga, puede volver a ejecutar el mismo comando make y se reanudará o volverá a intentar descargar los archivos que no se pudieron descargar durante la primera vez. Una vez que todos los archivos se hayan descargado con éxito, make informará que no hay nada más por hacer, por lo que no hay inconveniente en ejecutarlo un tiempo adicional para estar "seguros".

(El interruptor -k dice hacer para mantener la descarga del resto de los archivos incluso si una sola descarga fallara.)

+0

"-j 5" le dice a make que ejecute como máximo 5 comandos curl en paralelo. –

+0

Realmente es la mejor solución ya que permite reanudar las descargas fallidas y utiliza 'make', que es sólido y está disponible en cualquier sistema Unix. – nimrodm

31

Mi respuesta es un poco tarde, pero creo que todas las respuestas existentes caen sólo un poco corto. La forma en que hago este tipo de cosas es con xargs, que es capaz de ejecutar una cantidad específica de comandos en subprocesos.

El de una sola línea me gustaría utilizar es, simplemente:

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

Esto garantiza que alguna explicación. El uso de -n 1 indica xargs para procesar un solo argumento de entrada a la vez. En este ejemplo, los números 1 ... 10 se procesan por separado. Y -P 2 dice xargs para mantener 2 subprocesos en ejecución todo el tiempo, cada uno manejando un solo argumento, hasta que todos los argumentos de entrada hayan sido procesados.

Puede pensar en esto como MapReduce en el shell. O tal vez solo la fase de Mapa. De todos modos, es una forma efectiva de hacer un montón de trabajo mientras te aseguras de que no hagas explotar tu máquina. Es posible hacer algo similar en un bucle for en un shell, pero terminan haciendo gestión de procesos, lo que comienza a parecer bastante inútil una vez que te das cuenta de lo increíblemente genial que es este uso de xargs.

Actualización: sospecho que mi ejemplo con xargs podría mejorarse (al menos en Mac OS X y BSD con el indicador -J). Con paralelo GNU, el comando es un poco menos difícil de manejar, así:

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

También tenga en cuenta que si tiene una versión completa de xargs, simplemente puede hacer lo siguiente: 'seq 1 10 | xargs -I {} -P2 - curl -O -s 'http://example.com/?page {} .html'' – Six

2

Ejecutar un número limitado de proceso es fácil si su sistema tiene comandos como pidof o pgrep el cual, dado un nombre de proceso, devuelva el PID (el el recuento de los pids indica cuántos se están ejecutando).

Algo como esto:

#!/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 

para llamar así:

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

La línea de rizo de la secuencia de comandos no se ha probado.

Cuestiones relacionadas