web-dev-qa-db-ja.com

Curlコマンドラインユーティリティを使用した並行ダウンロード

Webサイトからいくつかのページをダウンロードしたいのですが、curlを使用して正常にダウンロードしましたが、ほとんどのダウンロードマネージャーと同じようにcurlが一度に複数のページをダウンロードするのではないかと思っていました。少しスピードアップしてください。 curlコマンドラインユーティリティでそれを行うことは可能ですか?

私が使用している現在のコマンドは

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

ここでは、1から10までのページをダウンロードして、1.htmlという名前のファイルに保存しています。

また、curlが各URLの出力を別のファイルURL.htmlに書き込むこともできます。ここで、URLは処理中のページの実際のURLです。

25
Ravi Gupta

まあ、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
27
nimrodm

私の答えは少し遅いですが、既存の答えはすべて少し足りないと思います。このようなことを行う方法は、サブプロセスで指定された数のコマンドを実行できるxargsを使用することです。

私が使用するワンライナーは、単に:

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

これはいくつかの説明が必要です。の用法 -n 1は、一度に1つの入力引数を処理するようにxargsに指示します。この例では、数字1 ... 10はそれぞれ個別に処理されます。そして-P 2は、すべての入力引数が処理されるまで、それぞれが単一の引数を処理する2つのサブプロセスを常に実行し続けるようにxargsに指示します。

これはシェルのMapReduceと考えることができます。または、おそらくマップフェーズだけかもしれません。とにかく、それはあなたがあなたのマシンをフォーク爆撃しないことを確実にしながら多くの仕事を成し遂げるための効果的な方法です。シェルのforループで同様のことを行うことは可能ですが、最終的にプロセス管理を行うことになります。これは、xargsのこの非常に優れた使用法がどれほど素晴らしいかを理解すると、かなり無意味に見え始めます。

更新:xargsを使用した私の例は改善できると思います(少なくともMac OS XとBSDでは-J 国旗)。 GNU Parallelの場合、コマンドも扱いにくくなります。

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

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.

以下は、必要な数の並行プロセスでcurlを自動的に起動するスクリプトです。 https://github.com/axelabs/splitcurl

5
AXE Labs

並列コマンドの起動には、由緒ある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
# $@ is the target filename e.g. 1.html
%.html:
        curl -C - 'http://www...../?page='$(patsubst %.html,%,$@) -o [email protected]
        mv [email protected] $@

[〜#〜] note [〜#〜]最後の2行は(8スペースの代わりに)TAB文字で始まる必要があります。そうでない場合、makeはファイルを受け入れません。

今すぐ実行します:

make -k -j 5

私が使用したcurlコマンドは、出力を1.html.tmpに格納し、curlコマンドが成功した場合にのみ、1.htmlに名前が変更されます(次の行のmvコマンドによって)。したがって、一部のダウンロードが失敗した場合、同じmakeコマンドを再実行するだけで、初回のダウンロードに失敗したファイルのダウンロードが再開/再試行されます。すべてのファイルが正常にダウンロードされると、makeはそれ以上実行する必要がないことを報告します。そのため、「安全」になるためにもう一度実行しても害はありません。

-kスイッチは、1回のダウンロードが失敗した場合でも、残りのファイルをダウンロードし続けるようmakeに指示します。)

5
Jonas Berlin

システムにpidofまたはpgrepのようなコマンドがあり、プロセス名を指定するとpidを返す場合、限られた数のプロセスを簡単に実行できます(pidの数は、実行中の数を示します)。

このようなもの:

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

スクリプトのカールラインはテストされていません。

2
Alex

fmtxargsに基づいたソリューションを思いつきました。アイデアは、中括弧http://example.com/page{1,2,3}.html内に複数のURLを指定し、xargsと並行して実行することです。以下は3つのプロセスでダウンロードを開始します:

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

したがって、ダウンロード可能な4行のURLが生成され、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

7.66.0以降、curlユーティリティには、単一の非ブロッキングプロセス内で複数のURLを並行してダウンロードするためのサポートが組み込まれました。これは、xargsとバックグラウンドのスポーン、ほとんどの場合:

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

これにより、18個のリンクが同時にダウンロードされ、18個の異なるファイルに並列に書き込まれます。 Daniel Stenbergによるこの機能の公式発表はこちらです https://daniel.haxx.se/blog/2019/07/22/curl-goez-parallel/

1

カールについてはわかりませんが、 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