手把手用 monolith 一键离线归档网页
告别浏览器“另存为”的繁琐流程。本文带你实战 monolith,从安装到掌握单页保存、资源过滤、批量归档及动态页面预处理,10 分钟学会将任意网页打包为自包含 HTML,彻底解决离线备份与分享难题。

别再一个个「另存为」了
上周帮同事整理技术方案参考,对方甩过来十几条链接让我帮忙保存。常规操作是:打开浏览器 → 右键另存为 → 生成一堆 HTML 加资源文件夹 → 打包 zip 发给对方。解压后偶尔还打不开,相对路径乱了。
这个流程太笨了。今天介绍一个 CLI 小工具 monolith,15.2k Star,Rust 编写,零运行时依赖,能把网页连同图片、CSS、JS 全部内联到单个 .html 文件里,离线打开效果跟在线一模一样。
读完本文,你将完成:从安装到实战,把一个带图片、样式、外部脚本的网页完整归档为单文件 HTML,并掌握批量保存、动态页面处理、资源过滤等进阶用法。
前置条件
- 操作系统:macOS / Linux / Windows 均可
- 会终端基本操作,无需编程基础
- 自行编译安装需提前装好 Cargo(Rust 包管理器)
快速安装
monolith 安装包管理几乎覆盖所有主流平台,挑适合你的:
macOS / Linux (Homebrew)
bash
brew install monolith
Windows (Winget)
bash
winget install --id=Y2Z.Monolith -e
跨平台安装(需 Rust 环境)
bash
cargo install monolith
安装完成后验证:
bash
monolith -V
看到版本号就准备就绪。首推包管理器安装,因为 monolith 是纯二进制工具,brew 或 winget 会自动下载预编译版本并放到 PATH,开箱即用,不需要处理编译依赖。内网环境或想用最新特性时,再考虑 cargo install 或从 GitHub Releases 下载预编译二进制。
核心用法:一行命令归档网页
最基础的用法只需要 URL 和输出路径:
bash
monolith https://lyrics.github.io/db/P/Portishead/Dummy/Roads/ -o portishead.html
执行过程:
- 发起 HTTP 请求获取目标 HTML
- 解析 HTML,识别所有
<link><img><script><style>等引用 - 逐一下载资源,转换为 data URL(如
data:image/png;base64,...) - 把内联后的资源替换回 HTML 文档,写入输出文件
双击生成的文件,断网状态下打开,内容与在线时完全一致。这就是和浏览器「另存为」的本质区别:不依赖本地资源目录,所有内容打包在一个文件里。
常用选项速查
| 选项 | 作用 | 适用场景 |
|---|---|---|
-o FILE |
输出到文件 | 必填 |
-i |
去掉图片 | 只需文字内容时减小体积 |
-c |
去掉 CSS | 纯数据提取 |
-j |
去掉 JavaScript | 去除追踪脚本、广告 |
-I |
隔离文档(强制内联所有资源) | 最常用的归档模式 |
-t 30 |
设置超时 30 秒 | 网络较差时 |
-k |
跳过 TLS 证书验证 | 内部测试环境证书不受信 |
不需要记住所有选项,-I 记住就够了。它表示彻底隔离,强制将 CSS、字体、图片全部转为内联 data URL,生成的 HTML 不依赖任何外部文件。
实战:归档技术文档并过滤广告追踪
假设要保存 Hacker News 首页供离线阅读,但不想带入 Google Analytics 追踪脚本和广告资源。
用域名黑名单过滤第三方资源
bash
monolith -I \
-B -d googleanalytics.com \
-B -d .google.com \
https://news.ycombinator.com/ \
-o hn-offline.html
-B -d <domain>表示黑名单指定域名,monolith会跳过从这些域名获取的资源。反过来用-d(白名单模式)可仅保留特定域名资源。
确认产物:
bash
ls -lh hn-offline.html
打开文件,Google Analytics 的 <script> 标签消失了,Hacker News 内容和样式完好。归档体积变成了完全自包含的单个 HTML。
进阶场景
处理 SPA / 动态渲染页面
monolith 不含 JS 引擎,只处理服务端首次返回的 HTML。Vue/React 等单页应用(内容由 JS 渲染),直接用它会拿到空白骨架。
解决方案:让 headless Chrome 先渲染 DOM,再 pipe 给 monolith
bash
chromium --headless \
--window-size=1920,1080 \
--run-all-compositor-stages-before-draw \
--virtual-time-budget=9000 \
--incognito \
--dump-dom \
https://github.com \
| monolith - -I -b https://github.com -o github-rendered.html
这段命令完成了两步:
- 无头 Chromium 打开页面,等待 9 秒让 JS 渲染完成,输出最终 DOM(
--dump-dom) - monolith 从标准输入读取 HTML(
-),以指定地址为 base URL,内联所有资源
这是官方推荐的动态内容处理方案。将其写成 shell 函数加入 .bashrc,以后 archive-dynamic <url> 一行搞定。
批量归档多个页面
实际工作很少只存一个页面。用简单 shell 循环实现批量:
bash
#!/bin/bash
## archive-list.sh: 逐行读取 urls.txt 并归档
while read -r url; do
name=$(echo "$url" | md5sum | cut -d' ' -f1)
echo "[归档中] $url"
monolith "$url" -I -t 30 -o "archive/${name}.html"
done < urls.txt
文件名用 MD5 值是因为 URL 中可能包含 / ? 等不合法字符。-t 30 保证单次请求最长 30 秒,避免任务卡住。
带认证的页面
bash
monolith https://username:password@internal.example.com/dashboard -o dashboard.html
支持 Basic Auth,URL 格式为标准 user:pass@host。
走代理
monolith 直接读取环境变量,无需额外参数:
bash
export https_proxy=http://proxy.corp.com:8080
monolith https://some.site/ -o saved.html
常见问题与踩坑
Q1: 生成的 HTML 文件很大?
正常。把所有图片、字体、视频全内联后体积膨胀是必然的。只需文字内容时,加 -i -c -j 去掉图片、CSS 和 JS 再试,通常能从几 MB 压缩到几十 KB。
Q2: 某些页面乱码?
用 -E utf-8 强制指定编码。部分老旧网站声明的 charset 和实际不符,可能解析出错。
Q3: 保存内容跟在线不一致?
大概率是 SPA 或异步加载内容。参考上方「动态页面处理」方案,用 headless Chrome 做预处理。
Q4: piped input 时 -I 和 -b 必须配对
从标准输入读取 HTML(cat local.html | monolith - ...)时,monolith 不知道原始 URL,相对路径资源无法解析。必须用 -b <base-url> 指定 base URL。
总结回顾
今天完成了这些:
- 选择适合系统的安装方式,一行命令装好 monolith
- 用
monolith <url> -o output.html完成第一次网页归档 - 用
-B -d <domain>过滤不需要的第三方资源 - 用 headless Chrome + pipe 搞定动态页面
- 用 shell 循环实现批量归档
monolith 的价值不在功能花哨,而在于把一个常见但繁琐的操作浓缩成一行命令。源码采用 CC0 公共领域许可,可以放心集成到公司项目或个人工具链。
下一步建议:把常用操作封装成 alias 或 Makefile target;需要更复杂的页面调度(定时抓取、条件过滤)时,可参考 monolith 的 Apify Actor 模式,或将其作为下游工具编写 Go / Node 编排脚本。
有什么保存场景搞不定,评论区聊聊。