linux 下载工具 wget 使用经验

七阶子
18 min, 3405 words

归类: 工具使用

标签: wget

简介

在 linux 系统中,有两款著名工具,curl 与 wget 可用于发送 http 网络请求及下载网 络文档。在最基本的用法中,这两个命令行工具在功能上似有重叠,都有非常多的选项参 数。但它们侧重点不同,curl 侧重实现单次网络请求,且有个孪生库 libcurl 可植入各 种编程语言。而 wget 就是侧重下载的纯命令行工具,默认将网络请求的回应文档保存为 本地文件,对于大文档支持断点下载,还支持递归下载整个网站至本地镜像,这就具备了 基础的爬虫功能!

用 curl 下载单个文件的默认行为与 wget 不同,它将回应输出至终端。要保存文件得指 定参数,例如:

$ wget http://www.expample.com/index.html
$ curl -O http://www.expample.com/index.html
$ wget -O filename.html http://www.expample.com/index.html
$ curl -o filename.html http://www.expample.com/index.html

前两个命令将按服务器文档名保存为 index.html ,后两个命令可显示指定保存为其他 文件名。注意最后一个 curl -o 是小写的 o

如果 wget 要将回应输出至终端,而不保存文件,则用 - 作为文件名,例如:

$ wget -O - http://www.expample.com/index.html
$ curl http://www.expample.com/index.html

本文剩余部分着重讲 wget 下载用法。详细参数选项请参考 man wget 文档。

单文件下载

下载单文件是 wget 默认行为,无需多讲。但是下载大文件(如软件安装包之类),加上 -c 选项可以支持断点下载,即如果下载到一半因网络中断或系统关闭重启等原因,利 用该 -c 可接着下载剩余内容,而无需重新下载。

$ wget http://www.expample.com/soft/big.tgz
$ wget -c http://www.expample.com/soft/big.tgz

也可以从 ftp 站点下载。另外,现在许多 http 服务器是由 cgi 脚本动态生成网页,使 用 -E 可将保存文件名改为 .html ,只要服务器响应内容类型确实是 text/html 之类。例如:

$ wget -E http://www.expample.com/cgi-bin/hot.cgi
$ wget -E http://www.expample.com/cgi-bin/hot.php

如果不加 -E 选项,这两个命令下载的内容将分别保存为 hot.cgihot.php 。 有了 -E 则保存为 hot.html 。当然也可以使用 -O hot.html 显示指定保存名。

避免重复下载

wget 默认使用网络 URL 开尾基部当作保存文件名,如果本地有同名文件存在,则自动加 上 .1 后缀改名。但是也有选项避免重复下载。

$ wget -N http://www.expample.com/file.html
$ wget -nc http://www.expample.com/file.html

-N 选项会比较本地的 file.html 与服务器上相应文档的时间戳,只有当服务上 的文件更新了才下载。这在从 ftp 站点更新文件更有用,因为现在的大多 htpp 服务器 都不只是发送静态文件了,动态生成的网页没有时间戳意义。

-nc 选项则无条件忽略下载本地已存在的同名文档。如果确信网站的文档很少更新 ,或动态生成的文档始终内容相同,就没必要使用 -N 先检查时间了(因为这反而多了 一步 HEAD 请求),直接用 -nc 跳过。当然你得保证自己或其他程序不会意义向下 载目录添加无关但恰好同名的文件,那也有可能导致跳过下载。

批量下载

如果一次性想下载多个文档,固然可以直接在命令行参数末尾添加多个 URL ,但更方便 的做法是先搜集 URL 地址保存在一个文件中,再用 -i 选项指定该文件。

$ wget -i links.txt
$ cat links.txt | wget -i -

这里参数文件 links.txt 的内容格式就是每行代表一个 URL。如果文件参数用 - 则 表示从标准输入读取,如此可与管道连用,由其他程序或脚本生成一系列 URL 列表,再 传给 wget 下载。

另一种常见情形是参数文件保存的不是单纯的一行行 URL ,而是规范的 html 文档,其 中包含一些 <a> 链接。如此可添加 -F 选项让 wget 解释该 html 文档,提取其中 <a> 元素的 href 属性,下载相应的 URL 文档。如果其中包含相对链接,还可以加 入 -B url 选项指定基础网址。相当于在该 html 文档头部加入了 <base href="url"> 声明。当然如果源文档已有 base 声明,就无需 -B 选项。另外,文件名不需一定以 .html 结尾,只要文件内容是规范的 html 文档。

$ wget -F -i index.html
$ wget -F -B http://www.example.com/ -i index.html

递归下载网站

既然 wget 能够解释一个本地 html 文档,提取其内的超链接批量下载更多网络文档,那 将该工作流程反复推进一步,就能实现递归下载了。-r 选项就是开启递归下载模式, 可以很轻易地下载整个网站(当然会受限于目标网站服务器的反爬虫技术配置)。

$ wget -r http://www.example.com/
$ wget -rp http://www.example.com/
$ wget -rp -l 5 http://www.example.com/

递归下载另有一个关键的选项参数,-l 表示递归深度,默认是 5 层,即从初始页面沿 着超链接最多扩展 5 层就停止收手了,避免可能的无限下载。-l0 表示只下载命令行 指定的初始页面,-l1 表示也同时下载能从初始页面直接访问到的链接。

另外一个有用选项 -p 表示下载页面所有需要的内容。这与 -l1 下载直接链接文档 不同,-p 还下载页面的其他内嵌元素,如图片,css 与 js 脚本等,目标是让下载的 文档可以离线浏览。意图下载整个网站时,-p 选项几乎也是必选的,故建议合并写成 -rp

$ wget -rp -np http://www.example.com/book/
$ wget -rp -L http://www.example.com/book/

选项 -np 表示只下载子网站的某个子目录。字母 pparent 缩写,-npno_parent 的意思。如上命令若初始参数是 http://www.example.com/book/ 就只会 下载 /book/ 子目录下的文档。-L 是相对链接之意,与 -np 选项意图类似,不过 它取决于下载文档内链接元素 href 的写法,只下载写成相对链接的 URL 。该参数不 再建议使用了,请只用 -np

如前所述,下载单文件时默认保存在当前目录。用 -i 批量下载时,也是当作许多并不 相关的单文档依次下载并保存在当前目录。但在递归下载时将要下载一批有组织的文档, wget 也就默认会保持网站目录结构。首先在当前目录下以初始 URL 参数的域名建个目录 ,如 www.expample.com/ ,然后将本次递归下载的所有的(本域)文档都放在该目录 中,并按网站目录构造各层级子目录,一一对应。

但是可用 -nH 选项让 wget 不建立域名顶层目录,直接将网站的层级目录建立在当前 目录下。不过也建议先手动建一个(稍短)的新目录,进入该新目录再下载,避免与之前 工作目录中已有文件混在一起。例如:

$ mkdir exsite
$ cd exsite
$ wget -rp -nH http://www.example.com
$ wget -rp -nd http://www.example.com

如果用 -nd 选项代替 -nH ,则不仅不建立顶层域名目录,也不建立网站的次级目录 ,也即将所有下载的文档都平坦地集中放在当前目录。如果这是符合工作所需,可加上该 选项试试。

递归下载网站时,网站内的跨域链接默认是不会下载的。否则如果某页有个指向百度或 google 的链接,那递归下载就扩大化了,可能下载到大量无关的网页与网站。但是如有 需要,可以加 -H 选项允许下载其他域名的网页,如此最好再加上 -D 选项明确指定 还接受哪些域名(可以是逗号分隔的多个域名)。例如:

$ wget -rp -H http://www.example.com
$ wget -rp -H -D images.example.com,www.other.com http://www.example.com

将网站下载到本地浏览,还另有一个需求,就是转换本地网页内的相互链接。用 -k 选 项可实现此目的,而大小的选项 -K 则在转换链接前备份网页文档,加个 .orig 后 缀。例如:

$ wget -rp -k http://www.example.com
$ wget -rp -k -K http://www.example.com
$ wget -rp -k -NK http://www.example.com

下载(备份)网站也许不是一次性的操作,后续也许需要更新式重下载,那就加上 -N 选项。因为 -k 转换链接后会修改文件的时间戳,最好再加上 -K 备份,那 wget 在 重新下载时就会拿备份的 .orig 原文档与服务器的新文档对比,确认有更新才下载。

如前所叙,另一个选项 -nc 是捡漏式地重新下载,因为若网站不是静态文件服务,很 可能时间戳不能良好维护。但该选项在递归下载时似乎会与 -k 选项冲突,如果用了 -k 转换本地链接,即使再加 -nc 还是会重复下载文档。不知这是 feature 还是 bug 。

-k 转换链接的另一个问题,是它要下载完所有文档才会修改本地链接,因为 wget 认 为只有到那时才能知晓哪些文档下载到本地了,哪些又没下载,才好有选择地修改指向已 下载的本地链接。这在下载非常大的网站时可能是个问题,因为一时会半会下载不完,又 或者下载到一半被网站管理员识破了爬虫,将其屏蔽了。

当然了,爬虫与反爬虫向来是斗智斗勇的故事。wget 在递归下载中也提供了一些选项使 之更像模拟浏览器访问。例如设置 user-agent (相当于浏览器类型)以及下载间隔:

$ wget -rp -U "Mozilla/5.0 Firefox/65.0" http://www.example.com
$ wget -rp -w1 http://www.example.com
$ wget -rp -w1 --random-wait http://www.example.com

-w 表示 wait ,成功下载一个网页后等多少秒再发起另一个请求,--random-wait 选项则更进一步,表示等待时间有点随机(平均期望还是 -w 指定的参数)。

此外,wget 下载也支持登陆验证、cookie 发送及 https 证书校验。这些概念略复杂, 具体要用到时请查手册,查相关选项参数的用法。

最后,在下载网站时若无特殊需求,也可直接用 -m 选项,它大约相当于 -rp -l inf -N 等参数的组合。

$ wget -m http:/www.example.com

后台下载

默认情况下,wget 在下载过程中,会向标准错误输出一些有关进度等的日志信息。如果 下载时间比较长,可以用 -b 将 wget 置于后台下载。此时将自动记录 wget-log 日志文件,例如:

$ wget -m -b http:/www.example.com
$ tail -f wget-log

后台下载的意义是,假使用 xshell 登陆远程服务器,执行 wget -b 后断开 xshell 链接,在远程服务器上的 wget 也将继续下载。如果没用 -b 选项,则 xshell 断开后 ,wget 也将中断。虽然在下载大文件时可用 -c 继续下载,但 -m 下载网站时重新 下载会更麻烦些。

当默认 wget-log 日志文件存在当前目录时,会自动重命名 wget-log.1 等。不过也 可用 -o logfile (小写 o )指定日志文件,这是覆盖式的,另有 -a logfile 选项是添加到已有日志文件末尾。

$ wget -m -b -o wget.log http:/www.example.com
$ wget -m -b -a wget.log http:/www.example.com

还有一个问题,wget 参数比较多,对于需要定制下载参数时,若每次在命令行输入大量 参数比较麻烦。一个解决方案是自行写个包装 shell 脚本,此时建议在脚本中都使用 长选项名如 --output-file --output-document 等,这比 -o -O 短选项更见名 思义,而命令行使用短选项是便于快捷输入。

另一个方案是使用 .wgetrc 启动配置文件。wget 的系统配置在 /etc/wgetrc ,用 户个人的配置在 ~/.wgetrc 。wget 每次启动都会读取其中的配置,个人配置在系统配 置之后读取,所以若有冲突,个人配置会覆盖系统配置。

此外,还可以为某个下载任务定制配置文件,例如保存为 example.wgetrc ,然后在命 令行中使用 --config-file 指定启动配置文件(将略过 ~/.wgetrc):

$ wget --config=./example.wgetrc http:/www.example.com
$ wget --config=./example.wgetrc -e "extra-name=value" http:/www.example.com

如此可大量简化命令行参数,可惜 --config 没有短选项名。wgetrc 配置文件是简 单的 name = value 格式配置,支持 # 开始的行注释。可用的配置名大致与长选项 名类似,但拼写上可能不完全一致,使用时再核对文档或 /etc/wgetrc 示例配置。

命令行还另有一个选项 -e ,可以将本该写在 wgetrc 的配置项临时写在命令行参数 ,这在需要额外补充配置又不想修改配置文件时有用,尤其是有些配置名没有相应的命令 行选项。

参考文献

  • https://www.gnu.org/software/wget/manual/
  • https://daniel.haxx.se/docs/curl-vs-wget.html