Параллельная загрузка с помощью утилиты командной строки 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/