curl
和都提供了下载连续范围的文件( in 、in )wget
的能力,但它们都有一个缺点:没有提供在序列中的每次下载之间暂停的简单方法。有些服务器在几次快速下载后会切断下载,无论如何,在下载之间暂停是礼貌和适当的,无论如何,要成为一个好的爬虫公民。例如,如果有人想在每个请求之间暂停 5 秒,我的理解是,如果没有额外的脚本,就没有办法做到这一点,这本质上破坏了通过发出单独的请求来对顺序范围提供内置支持的意义。[1-100]
curl
{1..100}
wget
curl
解决这个问题的方法是使用wget
具有方便--wait=5
标志的which来实现上述期望的结果。不幸的是,wget
还有其他问题。它似乎很难处理 URL 中的特殊字符,并且无法使用 URL 周围的引号,因为该范围{1..100}
似乎无法识别。这意味着有时需要手动转义特殊字符。这是可以管理的,但很烦人。
然而,更重要的是,wget
不支持动态命名输出(该-O
标志在这里没有帮助)。尽管curl
提供了便利,但如果不再次绕过内置顺序范围支持并制作单个请求的脚本化集合,或者在下载后必须或以其他方式编辑文件名,-o "#1.jpg"
似乎无法实现相同的动态结果。wget
rename
在我看来,这是一个相当常见的任务:下载一系列连续的源文件,在每个请求之间礼貌地暂停,并动态重命名输出。我是否缺少一些替代方案curl
并wget
克服上述两个问题:1)每个请求之间的暂停2)动态输出文件名。
答案1
它似乎很难处理网址中的特殊字符,并且无法使用网址周围的引号,因为范围 {1..100} 似乎无法识别。
这是因为这个范围语法实际上不是 的一个特性wget
,而是你的 shell(例如 bash)的一个特性,它扩展了参数前将它们传递给wget
,比较:
$ echo abc{1..5}
abc1 abc2 abc3 abc4 abc5
或者
$ ruby -e 'p ARGV' abc{1..5}
["abc1", "abc2", "abc3", "abc4", "abc5"]
如果您引用该参数,那么 shell 将不会扩展它:
$ echo 'abc{1..5}'
abc{1..5}
但是,您可以引用除范围之外的所有内容:
$ echo 'abc'{1..5}'def'
abc1def abc2def abc3def abc4def abc5def
然而,更重要的是,wget 不支持动态命名输出
wget
没有处理这样的范围的功能,因为这样的范围不是wget
功能。
所以不,看来你不能用一个命令来完成所有这些。但您仍然可以将其放入 oneliner 中:
for i in {1..100}; do curl "https://example.com/${i}.jpg" -o "output_${i}.jpg"; sleep 5; done
UNIX 工具被设计为相当集中但易于编写脚本。他们中的一些人已经提供了许多选项来一次性完成常见任务,但他们永远无法独自覆盖所有用例。
答案2
不是对“我可以在请求之间暂停”的直接回答,而是对成为“优秀的爬虫公民”的直接回答。
--limit-rate
在从端点收到“太多请求”后,我成功使用了该选项。必须反复试验,50K 才能完成我的任务。
curl --limit-rate 50k "https://someURL.com/resource?p=[1-100]" -o "path\to\file_#1.txt"
答案3
对于curl 7.84.0及更高版本,您可以使用--rate
中描述的参数这篇博文:
设置允许的最快速率,
--rate "N/U"
其中 N 是整数,U 是时间单位。支持的单位为“s”(秒)、“m”(分钟)、“h”(小时)和“d”(天,以 24 小时为单位)。 U是时间单位。如果未提供“/U”,则默认时间单位为每小时传输次数。例如,要使curl 执行其请求的速度不超过每分钟两次,请使用,
--rate 2/m
但如果您希望每小时执行25 次,则使用--rate 25/h
。
因此,要发送请求的频率不超过每 5 秒一次(诚然,这与请求之间暂停 5 秒不同),您可以使用--rate 12/m
.