使用Curl命令行实用程序并行下载

时间:2011-12-26 08:31:02

标签: linux shell unix curl

我想从网站下载一些页面并使用curl成功完成,但我想知道是否某种方式curl一次下载多个页面,就像大多数下载管理器一样,它会加速一点点。是否可以在curl命令行实用程序中执行此操作?

我正在使用的当前命令是

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

这里我从1到10下载页面并将它们存储在名为1.html的文件中。

此外,curl是否可以将每个网址的输出写入单独的文件URL.html,其中URL是正在处理的网页的实际网址。

10 个答案:

答案 0 :(得分:39)

我的回答有点迟了,但我相信所有现有的答案都会有点短暂。我这样做的方式是使用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个子进程一直运行,每个子进程处理一个参数,直到所有输入参数都被处理完毕。

你可以把它想象成shell中的MapReduce。或者也许只是地图阶段。无论如何,它是一种有效的方法来完成大量工作,同时确保您不会对您的机器进行分叉。可以在shell中的for循环中执行类似的操作,但最终会进行流程管理,一旦您意识到xargs的使用有多么精彩,这似乎毫无意义。

更新:我怀疑我的xargs示例可以改进(至少在Mac OS X和带有-J标志的BSD上)。使用GNU Parallel,命令也不那么笨拙:

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

答案 1 :(得分:24)

嗯,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 :(得分:5)

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

答案 3 :(得分: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
# $@ is the target filename e.g. 1.html
%.html:
        curl -C - 'http://www...../?page='$(patsubst %.html,%,$@) -o $@.tmp
        mv $@.tmp $@

注意最后两行应以TAB字符(而不是8个空格)开头,否则make将不接受该文件。

现在你运行:

make -k -j 5

我使用的curl命令将输出存储在1.html.tmp中,并且只有当curl命令成功时,它才会被重命名为1.html(通过下一行的mv命令) 。因此,如果某些下载失败,您只需重新运行相同的make命令,它将恢复/重试下载第一次无法下载的文件。一旦成功下载了所有文件,make将报告没有其他任何工作要做,所以再运行一次是“安全”没有任何害处。

-k开关告诉make继续下载其余文件,即使单个下载失败也是如此。)

答案 4 :(得分:2)

如果您的系统具有pidofpgrep之类的命令,则运行有限数量的过程很容易,在给定进程名称的情况下,返回pids(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)

脚本的卷曲线未经测试。

答案 5 :(得分:2)

curlwget 不能以并行块下载单个文件,但有替代方案:

  • aria2(用 C++ 编写,在 Deb 和 Cygwin 存储库中可用)

    aria2c -x 5 <url>
    
  • axel(用 C 编写,可在 Deb 存储库中找到)

    axel -n 5 <url>
    
  • wget2(用 C 编写,可在 Deb 存储库中找到)

    wget2 --max-threads=5 <url>
    
  • lftp(用 C++ 编写,在 Deb 仓库中可用)

    lftp -n 5 <url>
    
  • hget(用 Go 编写)

    hget -n 5 <url>
    
  • pget(用 Go 编写)

    pget -p 5 <url>
    

答案 6 :(得分:1)

我想出了一个基于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

答案 7 :(得分:1)

7.68.0 开始 curl 可以并行获取多个 url。此示例将从具有 3 个并行连接的 urls.txt 文件中获取网址:

curl --parallel --parallel-immediate --parallel-max 3 --config urls.txt

urls.txt:

url = "example1.com"
output = "example1.html"
url = "example2.com"
output = "example2.html"
url = "example3.com"
output = "example3.html"
url = "example4.com"
output = "example4.html"
url = "example5.com"
output = "example5.html"

答案 8 :(得分:0)

我不确定卷曲,但你可以使用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/

答案 9 :(得分:0)

从7.66.0开始,curl实用程序最终内置了对在单个非阻塞过程中并行下载多个URL的支持,与{{ 1}}和背景生成,在大多数情况下:

xargs

这将并行下载18个链接,并将它们写到18个不同的文件中,也同时进行。 Daniel Stenberg对此功能的正式公告在这里:https://daniel.haxx.se/blog/2019/07/22/curl-goez-parallel/