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

Linux 使用Curl命令行实用程序并行下载,linux,shell,unix,curl,Linux,Shell,Unix,Curl,我想从一个网站上下载一些页面,我使用curl成功地完成了下载,但我想知道curl是否会像大多数下载管理器那样一次下载多个页面,这样会稍微加快速度。是否可以在curl命令行实用程序中执行此操作 我当前使用的命令是 curl 'http://www...../?page=[1-10]' 2>&1 > 1.html 这里我下载了从1到10的页面,并将它们存储在名为1.html的文件中 另外,curl是否可以将每个URL的输出写入单独的文件,例如URL.html,其中URL是正在处

我想从一个网站上下载一些页面,我使用
curl
成功地完成了下载,但我想知道
curl
是否会像大多数下载管理器那样一次下载多个页面,这样会稍微加快速度。是否可以在
curl
命令行实用程序中执行此操作

我当前使用的命令是

curl 'http://www...../?page=[1-10]' 2>&1 > 1.html
这里我下载了从1到10的页面,并将它们存储在名为
1.html
的文件中


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

我不确定curl,但您可以使用


嗯,
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

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.
$man curl | grep-A2'\--range'
-r/--范围
(HTTP/FTP/SFTP/FILE)检索字节范围(即部分docu-
从HTTP/1.1、FTP或SFTP服务器或本地文件。

下面是一个脚本,它将自动启动curl,并具有所需数量的并发进程:

要启动并行命令,为什么不使用古老的
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 $@
注意最后两行应以制表符开头(而不是8个空格),否则make将不接受该文件

现在您只需运行:

make -k -j 5
我使用的curl命令将输出存储在
1.html.tmp
中,只有curl命令成功,它才会被重命名为
1.html
(通过下一行的
mv
命令)。因此,如果某些下载失败,您可以重新运行相同的
make
命令,它将恢复/重试下载第一次下载失败的文件。一旦成功下载了所有文件,make将报告没有更多的工作要做,所以为了“安全”再运行一次也没有坏处


(开关告诉make即使一次下载失败也要继续下载其余的文件。)

我的答案有点晚了,但我相信所有现有的答案都有点短。我这样做的方式是使用
xargs
,它能够在子流程中运行指定数量的命令

我将使用的一个班轮是:

$ seq 1 10 | xargs -n1 -P2 bash -c 'i=$0; url="http://example.com/?page${i}.html"; curl -O -s $url'
这需要一些解释。使用
-n1
指示
xargs
一次处理一个输入参数。在本例中,数字
1。。。10
分别进行处理。和
-p2
告诉
xargs
始终保持两个子进程运行,每个子进程处理一个参数,直到处理完所有输入参数

您可以将其视为shell中的MapReduce。或者可能只是地图阶段。不管怎样,这是一个有效的方法来完成大量的工作,同时确保你不会用叉子炸你的机器。可以在shell中的for循环中执行类似的操作,但最终会执行流程管理,一旦您意识到使用
xargs
有多么疯狂,这就变得毫无意义了

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

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

如果您的系统具有诸如
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)
这样称呼:

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

脚本的curl行未经测试。

我提出了一个基于
fmt
xargs
的解决方案。其思想是在大括号内指定多个URL
http://example.com/page{1,2,3}.html
并与
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.66.0开始,
curl
实用程序最终内置了在一个非阻塞过程中并行下载多个URL的支持,在大多数情况下,与
xargs
和后台生成相比,这应该更快、更节省资源:

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

这将并行下载18个链接,并将它们写入18个不同的文件,也是并行的。Daniel Stenberg对此功能的官方声明如下:

curl
wget
无法以并行块形式下载单个文件,但还有其他选择:

    < P>(用C++编写,可在DEB和CygWin RePO中使用)

    aria2c-x5
    
  • (用C书写,可在Deb回购协议中获得)

    axel-n 5
    
  • (用C书写,可在Deb回购协议中获得)

    wget2——最大线程数=5
    
  • < P>(用C++编写,可在DEB RePO中使用)< /P>
    lftp-n5
    
  • (用围棋书写)

    hget-n5
    
  • (用围棋书写)

    pget-p5
    

7.68.0开始,curl可以并行获取多个URL。此示例将使用3个parall从
urls.txt
文件中获取URL
axel -n 5 <url>
wget2 --max-threads=5 <url>
lftp -n 5 <url>
hget -n 5 <url>
pget -p 5 <url>
curl --parallel --parallel-immediate --parallel-max 3 --config 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"