Параллельная загрузка с помощью утилиты командной строки Curl

Я хочу загрузить несколько страниц с веб-сайта, и я сделал это успешно, используя curl, но мне было интересно, если каким-то образом curl загружает несколько страниц одновременно, как это делают большинство менеджеров загрузки, это ускорит работу немного. Возможно ли это сделать в утилите командной строки curl?

Текущая команда, которую я использую,

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

Здесь я загружаю страницы с 1 по 10 и сохраняю их в файле с именем 1.html.

Кроме того, возможно ли curl написать вывод каждого URL-адреса для разделения файла say URL.html, где URL является фактическим URL-страницей обрабатываемой страницы.

Ответ 1

Ну, curl - это простой процесс UNIX. У вас может быть столько процессов curl, которые выполняются параллельно, и отправка их результатов в разные файлы.

curl может использовать часть имени файла URL для создания локального файла. Просто используйте параметр -O (man curl для деталей).

Вы можете использовать что-то вроде следующего

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

Ответ 2

Мой ответ немного запоздалый, но я считаю, что все существующие ответы немного коротки. То, как я делаю такие вещи, это xargs, который способен запускать определенное количество команд в подпроцессах.

Однострочный я использую просто:

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

Это требует некоторого объяснения. Использование -n 1 инструктирует xargs обрабатывать один входной аргумент за раз. В этом примере номера 1 ... 10 обрабатываются отдельно. И -P 2 сообщает xargs, чтобы все 2 подпроцесса работали все время, каждый из которых обрабатывал один аргумент, пока все входные аргументы не были обработаны.

Вы можете думать об этом как о MapReduce в оболочке. Или, возможно, только фазу Карты. Независимо от того, это эффективный способ получить много работы, гарантируя, что вы не разблокируете свою машину. Возможно сделать что-то подобное в цикле for в оболочке, но в конечном итоге выполнить управление процессом, которое начинает казаться довольно бессмысленным, как только вы осознаете, насколько безумно это использование xargs.

Обновление. Я подозреваю, что мой пример с xargs может быть улучшен (по крайней мере, в Mac OS X и BSD с флагом -J). С помощью GNU Parallel команда немного менее громоздка:

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

Ответ 3

Curl также может ускорить загрузку файла, разбив его на части:

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

Вот script, который автоматически запустит завиток с нужным количеством одновременных процессов: https://github.com/axelabs/splitcurl

Ответ 4

Для запуска параллельных команд, почему бы не использовать почтенную утилиту командной строки make. Она поддерживает параллельное выполнение и отслеживание зависимостей и многое другое.

Как? В каталоге, где вы загружаете файлы, создайте новый файл с именем Makefile со следующим содержимым:

# 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]

ПРИМЕЧАНИЕ Последние две строки должны начинаться с символа TAB (вместо 8 пробелов) или make не будут принимать файл.

Теперь вы просто запускаете:

make -k -j 5

Команда curl, которую я использовал, сохранит вывод в 1.html.tmp, и только если команда curl завершится успешно, она будет переименована в 1.html (командой mv на следующей строке). Таким образом, если некоторая загрузка не удалась, вы можете просто повторно запустить ту же команду make, и она возобновит/повторит загрузку файлов, которые не были загружены в первый раз. После того, как все файлы будут успешно загружены, make сообщит, что больше нечего делать, поэтому нет вреда в том, чтобы запустить дополнительное время, чтобы быть "безопасным".

(Переключатель -k сообщает make продолжать загрузку остальных файлов, даже если одна загрузка не работает.)

Ответ 5

Запустить ограниченное количество процессов легко, если в вашей системе есть команды типа pidof или pgrep, которые, учитывая имя процесса, возвращают pids (подсчет числа указывает, сколько из них работает).

Что-то вроде этого:

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

для вызова следующим образом:

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

Линия завивки script не проверена.

Ответ 6

Я не уверен в завитке, но вы можете сделать это с помощью 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/