web-dev-qa-db-fra.com

Téléchargement parallèle à l'aide de l'utilitaire de ligne de commande Curl

Je veux télécharger certaines pages d'un site Web et je l'ai fait avec succès en utilisant curl mais je me demandais si curl télécharge plusieurs pages à la fois comme le font la plupart des gestionnaires de téléchargement, il le fera accélérer un peu les choses. Est-il possible de le faire dans l'utilitaire de ligne de commande curl?

La commande actuelle que j'utilise est

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

Ici, je télécharge des pages de 1 à 10 et les stocke dans un fichier nommé 1.html.

De plus, est-il possible que curl écrive la sortie de chaque URL pour séparer le fichier, par exemple URL.html, où URL est l'URL réelle de la page en cours de traitement.

25
Ravi Gupta

Eh bien, curl n'est qu'un simple processus UNIX. Vous pouvez avoir autant de ces processus curl qui s'exécutent en parallèle et envoient leurs sorties à différents fichiers.

curl peut utiliser la partie nom de fichier de l'URL pour générer le fichier local. Utilisez simplement le -O option (man curl pour plus de détails).

Vous pouvez utiliser quelque chose comme le suivant

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
27
nimrodm

Ma réponse est un peu tardive, mais je pense que toutes les réponses existantes sont un peu courtes. La façon dont je fais des choses comme ça est avec xargs, qui est capable d'exécuter un nombre spécifié de commandes dans des sous-processus.

Le one-liner que j'utiliserais est simplement:

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

Cela mérite une explication. L'utilisation de -n 1 demande à xargs de traiter un seul argument d'entrée à la fois. Dans cet exemple, les nombres 1 ... 10 sont chacun traités séparément. Et -P 2 indique à xargs de maintenir 2 sous-processus en cours d'exécution, chacun traitant un seul argument, jusqu'à ce que tous les arguments d'entrée aient été traités.

Vous pouvez penser à cela comme MapReduce dans le Shell. Ou peut-être juste la phase Carte. Quoi qu'il en soit, c'est un moyen efficace de faire beaucoup de travail tout en vous assurant de ne pas bombarder votre machine. Il est possible de faire quelque chose de similaire dans une boucle for dans un shell, mais finissez par faire de la gestion des processus, qui commence à sembler assez inutile une fois que vous réalisez à quel point cette utilisation de xargs est incroyablement géniale.

Mise à jour: je soupçonne que mon exemple avec xargs pourrait être amélioré (au moins sur Mac OS X et BSD avec le -J drapeau). Avec GNU Parallel, la commande est également un peu moins lourde:

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

Curl peut également accélérer le téléchargement d'un fichier en le divisant en plusieurs parties:

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

Voici un script qui lancera automatiquement curl avec le nombre souhaité de processus simultanés: https://github.com/axelabs/splitcurl

5
AXE Labs

Pour lancer des commandes parallèles, pourquoi ne pas utiliser l'utilitaire de ligne de commande vénérable make. Il prend en charge l'exécution parallèle et le suivi des dépendances et ainsi de suite.

Comment? Dans le répertoire où vous téléchargez les fichiers, créez un nouveau fichier appelé Makefile avec le contenu suivant:

# 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
# $@ is the target filename e.g. 1.html
%.html:
        curl -C - 'http://www...../?page='$(patsubst %.html,%,$@) -o [email protected]
        mv [email protected] $@

NOTE Les deux dernières lignes doivent commencer par un caractère TAB (au lieu de 8 espaces) ou make n'acceptera pas le fichier.

Vous lancez maintenant:

make -k -j 5

La commande curl que j'ai utilisée stockera la sortie dans 1.html.tmp et seulement si la commande curl réussit, elle sera renommée 1.html (par la commande mv sur la ligne suivante). Ainsi, si un téléchargement échoue, vous pouvez simplement réexécuter la même commande make et il reprendra/réessayera le téléchargement des fichiers qui n'ont pas pu être téléchargés la première fois. Une fois que tous les fichiers ont été téléchargés avec succès, make indiquera qu'il n'y a plus rien à faire, donc il n'y a aucun mal à l'exécuter une fois de plus pour être "sûr".

(Le -k le commutateur indique à make de continuer à télécharger le reste des fichiers même si un seul téléchargement devait échouer.)

5
Jonas Berlin

Exécuter un nombre limité de processus est facile si votre système a des commandes comme pidof ou pgrep qui, étant donné un nom de processus, retournent les pids (le nombre de pids indique combien sont en cours d'exécution).

Quelque chose comme ça:

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

appeler comme ça:

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

La ligne de bouclage du script n'est pas testée.

2
Alex

J'ai trouvé une solution basée sur fmt et xargs. L'idée est de spécifier plusieurs URL entre accolades http://example.com/page{1,2,3}.html et exécutez-les en parallèle avec xargs. Ce qui suit commencerait le téléchargement en 3 processus:

seq 1 50 | fmt -w40 | tr ' ' ',' \
| awk -v url="http://example.com/" '{print url "page{" $1 "}.html"}' \
| xargs -P3 -n1 curl -o

donc 4 lignes d'URL téléchargeables sont générées et envoyées à xargs

curl -o http://example.com/page{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}.html
curl -o http://example.com/page{17,18,19,20,21,22,23,24,25,26,27,28,29}.html
curl -o http://example.com/page{30,31,32,33,34,35,36,37,38,39,40,41,42}.html
curl -o http://example.com/page{43,44,45,46,47,48,49,50}.html
2
Slava Ignatyev

Depuis la version 7.66.0, l'utilitaire curl prend enfin en charge les téléchargements parallèles de plusieurs URL au sein d'un même processus non bloquant, ce qui devrait être beaucoup plus rapide et plus efficace en termes de ressources que xargs et le frai de fond, dans la plupart des cas:

curl -Z 'http://httpbin.org/anything/[1-9].{txt,html}' -o '#1.#2'

Cela va télécharger 18 liens en parallèle et les écrire dans 18 fichiers différents, également en parallèle. L'annonce officielle de cette fonctionnalité par Daniel Stenberg est ici: https://daniel.haxx.se/blog/2019/07/22/curl-goez-parallel/

1
Andrew Pantyukhin

Je ne suis pas sûr de curl, mais vous pouvez le faire en utilisant 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/
0
zengr