前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版

常用命令之wget使用记录,断点续传与整站镜像

首页2018-12-04 11:00:45Back-End
Linuxwget下载

在服务器上装东西的时候,十有八九第一条命令就是 wget。下一个 tar 包、拉一份安装脚本、把某个域名下的静态资源整个扒下来,都靠它。但真用起来会发现几个别扭的地方:明明加了 -c 却还是从头下;-O 和 -P 长得像却完全不是一回事;抓整站的时候一不留神把半个互联网都爬下来了。

这些坑背后都有具体的原因,不是 wget 在为难你。这篇把 wget 的常用参数按使用场景理一遍,重点讲清楚参数背后在做什么,以及它和 curl 各自适合的活。

在本篇文章中,我们将从浅入深,和大家一起学习以下知识:

  • wget 和 curl 的分工,什么时候该用哪个
  • 下载单个文件,-O 和 -P 到底差在哪
  • 批量下载 -i、后台下载 -b 和日志文件去了哪
  • 断点续传 -c 的前提条件,为什么有时候它不生效
  • 限速 --limit-rate 和配额 -Q,别把带宽吃满
  • 递归下载和整站镜像,--mirror、-p、--convert-links、--no-parent 怎么配合
  • 证书报错、被反爬拦截、FTP 下载这几种情况怎么处理
  • 写进脚本时必须加的超时和重试

# 一、先说结论,wget 和 curl 怎么分工

这两个命令功能有重叠,但设计目标完全不同。

wget 是个下载器。它默认把内容存成文件,天然支持递归、断点续传、后台运行、失败重试。你要的是「把东西弄到本地」,wget 一条命令就够。

curl 是个数据传输工具,更准确说是个 HTTP 客户端瑞士军刀。它默认把响应打到标准输出,强项是构造请求(自定义方法、请求头、请求体、认证),以及看清楚一次请求的每个环节。你要的是「调这个接口」或者「搞清楚这个请求哪一步慢」,那是 curl 的活。我之前写过一篇 学会用Curl调试接口,从常用参数到耗时排查,接口调试那一侧的细节都在那边。

一句话记:下载用 wget,调试用 curl。

还有个实际差别,curl 几乎所有系统都自带(macOS、各种 Linux 发行版、Windows 10 之后),wget 在 macOS 和一些精简的容器镜像里需要自己装。写通用脚本的时候这点得考虑进去。

# 二、下载单个文件,以及 -O 和 -P 的区别

最基础的用法,什么参数都不带。

wget http://www.baidu.com
@前端进阶之旅: 代码已经复制到剪贴板

这条命令会在当前目录下生成一个 index.html。文件名是 wget 根据 URL 推出来的,URL 末尾没有具体文件名时它就用 index.html 兜底。

想指定存到哪、叫什么名字,用 -O(大写字母 O,不是数字 0)。

wget -O /home/index http://www.baidu.com
@前端进阶之旅: 代码已经复制到剪贴板

这里的 -O 是 output document,它给的是完整的输出路径加文件名,不是目录。写成 -O /home/ 会直接报错。

想只指定目录、文件名保持服务器给的那个,用的是 -P。

wget -P /home/downloads/ http://example.com/pkg/app-1.2.3.tar.gz
@前端进阶之旅: 代码已经复制到剪贴板

这两个参数搞混是很常见的事。我的记法是,-O 里的 O 是 output file,-P 里的 P 是 prefix(目录前缀)。

-O - 这个写法值得单独提一句,把文件内容输出到标准输出,可以直接接管道。安装脚本经常这么写。

wget -qO- https://example.com/install.sh | bash
@前端进阶之旅: 代码已经复制到剪贴板

-q 是安静模式,不打印进度条,不然进度信息会污染管道。顺带说一句,这种「下载即执行」的写法方便归方便,但你等于把机器交给了那个 URL,公司内网的脚本还好,来路不明的地址建议先下下来看一眼再跑。

# 三、批量下载、后台下载和日志

URL 多的时候,一条条敲太累。把它们写进一个文本文件,一行一个,然后用 -i。

wget -i file.txt
@前端进阶之旅: 代码已经复制到剪贴板

file.txt 里每行一个 URL,wget 会按顺序挨个下。原文这段写成了「会下载两个两个文件」,是个笔误,意思是文件里写几个 URL 就下几个。

下载大文件时终端不能一直占着,用 -b 转后台。

wget -b http://example.com/big.tar.gz
@前端进阶之旅: 代码已经复制到剪贴板

执行之后终端立刻返回,下载在后台继续。这时候进度信息去哪了?wget 会在当前目录生成一个 wget-log 文件,所有输出都写在里面。原文写的是 web-log,实际的默认文件名是 wget-log(同名文件已存在时会依次生成 wget-log.1、wget-log.2)。想看进度的话 tail -f wget-log 就行。

自己指定日志文件名用 -o(小写 o)。

wget -o dw.txt http://www.baidu.com
@前端进阶之旅: 代码已经复制到剪贴板

注意 -o 是覆盖写,同一个日志文件跑第二次前一次的记录就没了。想追加用 -a。

到这里已经有三个长得很像的参数了,-O 输出文件、-o 日志文件、-P 目录前缀。大小写在 wget 里是硬语义,这点跟 scp 的 -P/-p 是一个性质。

# 四、断点续传,以及它为什么有时候不生效

-c 是 wget 最实用的参数,尤其在网络不稳的机器上。

wget -c http://example.com/big.tar.gz
@前端进阶之旅: 代码已经复制到剪贴板

它的原理是这样:wget 看到本地已经有个同名文件且大小是 N 字节,就在请求里带上 Range: bytes=N- 这个头,请求服务端只发 N 之后的部分。服务端支持的话返回 206 Partial Content,接着写;不支持的话返回完整的 200,那就只能从头下。

所以 -c 能不能生效,取决于服务端支不支持 Range 请求。这不是你能控制的。判断方法也简单,用 curl -I 看一眼响应头里有没有 Accept-Ranges: bytes。

这里有个坑要注意,-c 和 -O 一起用容易出问题。-c 靠的是「本地文件大小」推断续传起点,而 -O 改了文件名之后,续传逻辑在某些情况下会判断失误,甚至把已有内容截断。要断点续传就别自作聪明改名,让 wget 用服务器给的文件名,下完了再 mv。

配合重试参数一起用效果更好。

wget -c --tries=5 --waitretry=10 -T 30 http://example.com/big.tar.gz
@前端进阶之旅: 代码已经复制到剪贴板

--tries=5 最多重试 5 次(原文写的是 --tries=3,含义一样),--waitretry=10 每次重试前的等待秒数,-T 30 是超时时间。三个配上之后,网络抖一下不会直接失败退出。

--tries=0 或者 --tries=inf 是无限重试。写在无人值守的脚本里要谨慎,服务端要是永久性 404,你的脚本就会一直转下去。

# 五、限速和配额,别把带宽吃满

在共用的机器或者办公网上下大文件,不限速是不礼貌的行为,严重的时候会把整条链路打满。

wget --limit-rate=100k -O zfj.html http://www.baidu.com
@前端进阶之旅: 代码已经复制到剪贴板

--limit-rate 的单位可以是 k 或者 m。要说明的是,它限制的是平均速度而不是瞬时速度,wget 的做法是下一小段就停一会儿,所以刚开始那几秒可能会冲得比较高,之后才稳定下来。

多文件下载时还可以设总配额。

wget -Q5m -i file.txt
@前端进阶之旅: 代码已经复制到剪贴板

下满 5MB 就停。这个参数只在下载多个文件时有效,单个文件下到一半不会被它掐断,wget 的策略是不做残缺文件。这一点原文有提到,是对的。

还有个 --wait=秒数,控制每个文件之间的间隔。抓一批资源的时候加上,对目标站客气一点,也降低被限流的概率。--random-wait 会在这个值上下随机浮动。

# 六、递归下载和整站镜像

这块是 wget 相对 curl 最大的优势,curl 完全没有递归能力。

先说最常见的诉求,把一个页面连同它依赖的 CSS、JS、图片一起存下来,离线也能打开。

wget --mirror -p --convert-links -P ./test http://localhost
@前端进阶之旅: 代码已经复制到剪贴板

拆开看这四个参数各自在干什么。

  • --mirror 打开镜像模式,它是一组参数的简写,相当于开启递归、不限递归深度、保留时间戳、保留目录列表
  • -p 下载显示这个页面所必需的全部文件,也就是图片、样式表、脚本这些
  • --convert-links 下载完成后把 HTML 里的链接改写成本地相对路径,这样双击打开也能正常跳转
  • -P ./test 所有内容存到 ./test 目录下

不加 --convert-links 的话,你本地打开那个 HTML,里面的链接还是指向原站,断网就是一片白板。这个参数是「离线可用」的关键。

这里必须提醒一句,--mirror 是不限深度的,用它之前一定要想清楚边界在哪。

站点有外链的话,理论上它会顺着爬到别人家去。控制范围主要靠这两个参数:--no-parent(简写 -np)禁止往上级目录爬,--domains 限定只在指定域名内递归。抓某个文档目录的时候,我一般是这么写的。

wget -r -np -p --convert-links --domains example.com -P ./docs https://example.com/guide/
@前端进阶之旅: 代码已经复制到剪贴板

按类型筛选用 -A(accept)和 -R(reject)。

wget -r -A .png http://www.baidu.com
wget --reject=png --mirror -p --convert-links -P ./test http://localhost
@前端进阶之旅: 代码已经复制到剪贴板

第一条只要 PNG,第二条是把 PNG 排除在外。注意这两个参数过滤的是最终要保存的文件,wget 还是得先把 HTML 页面下下来解析链接,所以它并不能减少请求数,只能减少落盘的文件。

递归下载还有个 -l 参数控制深度,-l 2 就是只往下两层。不确定站点结构的时候,先用小的深度试一次,看看抓下来多少东西再放大,比直接 --mirror 稳妥得多。

# 七、访问不通的几种情况

# 7.1 证书报错

老服务器上 wget 链接的 CA 证书包过期,或者对方用了自签证书,会直接报证书验证失败。

wget --no-check-certificate https://example.com/pkg.tar.gz
@前端进阶之旅: 代码已经复制到剪贴板

原文这条命令末尾多了个全角的 ·,是个手误,我一并去掉了。

这个参数的代价要说清楚,加上它等于把 TLS 的身份校验整个关掉,中间人可以随便替换你下载的内容。装软件包的场景下这尤其危险,你以为下的是官方包,实际可能是被掉包过的。临时应急可以,长期方案应该是更新系统的 CA 证书包,或者用 --ca-certificate 把对方的根证书指给 wget。

# 7.2 被当成爬虫拦下来

不少站点会看 User-Agent,wget 的默认 UA 里明晃晃写着自己是 wget,容易被 403。

wget --user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" https://example.com/file.zip
@前端进阶之旅: 代码已经复制到剪贴板
fe
  • 一、先说结论,wget 和 curl 怎么分工
  • 二、下载单个文件,以及 -O 和 -P 的区别
  • 三、批量下载、后台下载和日志
  • 四、断点续传,以及它为什么有时候不生效
  • 五、限速和配额,别把带宽吃满
  • 六、递归下载和整站镜像
  • 七、访问不通的几种情况
    • 7.1 证书报错
    • 7.2 被当成爬虫拦下来
    • 7.3 先探一下通不通
    • 7.4 FTP 下载
  • 八、写进脚本时该加什么
  • 总结
  • 参考

← Promise.all、race、allSettled、any 四个组合方法怎么选Linux之scp传输文件,从基础用法到rsync取舍 →