Kage:一键把任意网站打包成离线单文件,再也不会「页面已失效」

Kage:一键把任意网站打包成离线单文件,再也不会「页面已失效」

Ren Echo Lv4

你一定遇到过这种场景:精心收藏的网页,半年后再打开变成一片空白——JS 崩了、CDN 挂了、甚至整个站点都下线了。传统的「右键另存为」从来不是真正的保存,你存下的只是一个指向别人服务器的薄客户端。今天介绍一个刚刚在 Hacker News 上爆火的 Go 语言项目 Kage(影),它用 Headless Chrome 渲染页面后剥离全部 JavaScript,把网站变成可以离线浏览的纯净归档,甚至能打包成一个可执行文件。

🎯 一个困扰所有人的问题:网页保存 ≠ 真的保存

我们先来聊聊痛点。

在 Web 技术日益复杂的今天,一个网页背后可能挂着几十个第三方脚本——分析追踪、广告投放、A/B 测试框架、动态渲染引擎……你用浏览器「保存网页」时,保存的只是一个 HTML 壳加上一堆外部引用。等到 CDN 域名变更、JS 托管服务下线、或者某个关键 API 停服,你保存的页面就变成了一具空壳。

传统的「保存网页」方式,存下的只是一堆外部引用

更讽刺的是,很多「值得保存」的页面恰恰是最依赖 JavaScript 的——单页应用(SPA)、交互式文档、数据可视化面板……这些内容在断网环境下完全无法使用。

Kage 的核心理念:用真实浏览器渲染完页面,拿到最终 DOM 快照,然后把所有脚本彻底删除。留下的只有 HTML、CSS、图片和字体——全部本地化,零网络依赖。

🔧 底层硬核拆解:Kage 是如何工作的?

Kage 的工作流程可以概括为一条清晰的 pipeline:

1
种子 URL → Headless Chrome 渲染 → 最终 DOM 快照 → JS 剥离 → 资源本地化 → 磁盘写入

让我们拆开每一层来看:

1. Headless Chrome 渲染层

Kage 使用真实的 Chrome/Chromium 浏览器来渲染页面。这意味着:

  • 完整的 JavaScript 执行:页面在渲染阶段会完整运行所有 JS,包括动态加载内容、AJAX 请求、懒加载图片等
  • CSS 完整解析:所有的 CSS 变量、动画、媒体查询都会被正确处理
  • 真实的用户视角:Kage 会等待页面「稳定」后才截图,确保你看到的是最终状态,而不是某个中间态

这和传统的 wgetcurl 抓取有本质区别——那些工具只能拿到服务器返回的原始 HTML,而很多现代网站在客户端还有大量渲染逻辑。

2. DOM 快照层

Chrome 渲染完成后,Kage 会抓取当前的 DOM 状态作为快照。这个快照包含了:

  • 动态生成的 HTML 结构(比如 React/Vue 渲染出的组件)
  • 已加载的图片和媒体资源
  • 应用后的 CSS 样式

3. JavaScript 剥离层(核心!)

这是 Kage 最关键的步骤。它会从 DOM 中移除:

  • 所有 <script> 标签
  • 所有内联事件处理器(onclickonload 等)
  • 所有 javascript: 协议的 URL
  • 所有会触发远程请求的元素

剥离后的页面是一个「纯静态」的 HTML 文件,没有任何可执行代码。

4. 资源本地化层

Kage 会把页面引用的所有外部资源下载到本地:

  • CSS 文件:下载并重写其中的 url() 引用
  • 图片:下载到本地 _kage/ 目录
  • 字体文件:同样本地化

所有链接都被重写为镜像内的相对路径,确保完全离线可用。

5. 确定性 URL 映射

Kage 使用一套确定性的 URL 到本地路径映射规则(urlx 包),这意味着:

  • 同一个 URL(无论带不带 https://、带不带尾部斜杠)始终映射到同一个文件
  • 镜像是幂等的:相同页面不会被重复抓取
  • 可以安全地中断后恢复

🚀 全流程跑通指南:5 分钟上手 Kage

安装

方式一:Go 直接安装(推荐)

1
go install github.com/tamnd/kage/cmd/kage@latest

方式二:Docker(无需安装 Chrome)

1
docker run --rm -v "$PWD/out:/out" ghcr.io/tamnd/kage clone paulgraham.com

方式三:预编译二进制

GitHub Releases 下载对应平台的包,支持:

  • Linux(.tar.gz.deb.rpm.apk
  • macOS(.tar.gz
  • Windows(.zip
  • FreeBSD

⚠️ Kage 依赖 Chrome 或 Chromium。它会自动查找系统安装的 Chrome,也可以通过 --chrome 参数或 KAGE_CHROME 环境变量指定路径。

基础用法:克隆网站

1
2
3
4
5
6
7
8
9
10
11
# 克隆整个网站,默认保存到 $HOME/data/kage/<域名>/
kage clone paulgraham.com

# 限制页面数量和爬取深度
kage clone paulgraham.com --max-pages 50 --max-depth 2

# 只克隆网站的某个路径前缀
kage clone go.dev --scope-prefix /doc

# 包含子域名,并自动滚动触发懒加载
kage clone example.com --subdomains --scroll

离线浏览

1
2
3
# 启动本地 HTTP 服务器预览
kage serve $HOME/data/kage/paulgraham.com
# 访问 http://127.0.0.1:8800

打包成单文件

这是 Kage 最酷的功能——把整个镜像压缩成一个文件:

ZIM 归档格式

1
2
kage pack paulgraham.com               # 生成 paulgraham.com.zim
kage open paulgraham.com.zim # 用 kage 打开

ZIM 是一个开放的文件格式,专门用于将网站内容打包成单个压缩、索引、只读的文件。它也是 Kiwix 项目的底层格式——就是那个让你在没网的船上也能看维基百科的神器。

你可以用 Kiwix 的桌面应用或手机 App 直接打开 Kage 生成的 .zim 文件:

1
2
3
kiwix-serve paulgraham.com.zim          # Kiwix 服务器
# 或者双击文件用 Kiwix 桌面应用打开
# 或者传到手机用 Kiwix for Android/iOS 阅读

自包含可执行文件

1
2
kage pack paulgraham.com --format binary -o paulgraham
./paulgraham # 直接运行,无需安装任何东西

这个可执行文件包含了完整的 Kage 运行时和网站数据。你可以把它发给任何人——他们不需要安装 Kage,不需要安装 ZIM 阅读器,甚至不需要网络连接。双击就能浏览整个网站。

更妙的是,你可以跨平台构建:

1
2
3
# 在 Mac 上构建 Windows 版本的查看器
kage pack paulgraham.com --format binary --base kage-windows-amd64.exe
# 生成 paulgraham.exe

原生窗口模式(非浏览器标签页)

默认情况下打包的二进制会在系统浏览器中打开,但你可以编译一个带 webview 标签的版本,让网站在独立的原生窗口中显示:

Paul Graham 的文章在 kage 原生窗口中离线浏览

1
2
3
4
# 需要 cgo,链接系统 WebView(macOS: WKWebView, Windows: WebView2, Linux: WebKitGTK)
make build-webview
kage pack paulgraham.com --format binary --base bin/kage -o paulgraham
./paulgraham # 打开一个原生窗口,而不是浏览器标签

增量更新

1
2
# 重新渲染已有的镜像,捕获新内容
kage clone paulgraham.com --refresh

Kage 的爬取是幂等的——它会记住已经访问过的页面(存储在 _kage/state.json 中),中断后重启会从断点继续。

📊 Kage vs 传统方案对比

特性 wget 浏览器另存为 SingleFile Kage
JS 执行 部分
JS 彻底剥离
资源本地化 部分 部分
单文件打包
自包含可执行
ZIM 标准格式
断点续传
跨平台查看器

🏗️ 项目架构一览

Kage 的代码组织非常清晰,按职责拆分:

1
2
3
4
5
6
7
8
9
10
cmd/kage/     入口:固定主线程,交给 cli.Execute
cli/ Cobra 命令树和参数绑定
clone/ 爬取引擎:前端队列、渲染 Worker、资产 Worker、恢复状态
browser/ Headless Chrome 控制和 DOM 快照
sanitize/ JS 剥离:脚本、事件处理器、javascript: URL
asset/ 下载和本地化 CSS、图片、字体
urlx/ 确定性 URL 到路径的映射
zim/ 纯 Go 实现的 ZIM 读写器
pack/ 镜像到 ZIM 或自包含二进制
viewer/ 展示层:系统浏览器或原生窗口

整个项目用 Go 编写,纯 Go 构建时 CGO_ENABLED=0,只有原生窗口模式需要 cgo。

💡 使用场景与最佳实践

适合用 Kage 的场景

  1. 技术文档归档:把某个开源项目的文档站镜像下来,即使项目以后改版或下线也能查阅
  2. 学术论文保存:Paul Graham 的文章、Stripe 的技术博客等经典内容
  3. 弱网/离线环境:出差、飞行、偏远地区的离线阅读需求
  4. 数据归档:法律要求保存的网页快照,Kage 的确定性打包保证了内容一致性
  5. 知识库迁移:从一个平台迁移到另一个平台时的中间归档

使用建议

  • 对于大型网站,先用 --max-pages--max-depth 限制范围
  • 使用 --scope-prefix 只抓取你关心的部分
  • --scroll 触发懒加载内容
  • 定期 --refresh 更新镜像
  • 用 ZIM 格式长期归档,用二进制格式分发分享

📺 相关视频

标题 来源
Web Scraping with Go 全教程 Bilibili
Headless Chrome 自动化入门 Bilibili
Kiwix 离线维基百科使用教程 Bilibili

🔗 相关链接


Kage 虽然才发布一天(2026-06-14),但已经在 Hacker News 上收获了 385+ 点赞,GitHub 星标突破 650。它解决了一个真实存在但长期被忽视的问题——我们以为自己在「保存网页」,其实只是在保存一串指向别人服务器的链接。Kage 让网页真正属于你。

如果你经常需要保存网页内容,或者在弱网环境下工作,强烈建议试试这个工具。Go 安装一行命令,5 分钟就能上手。


本文作者 Ren Echo,专注 AI 与开发者工具深度评测。觉得有用的话,欢迎点赞收藏分享 👋

  • 标题: Kage:一键把任意网站打包成离线单文件,再也不会「页面已失效」
  • 作者: Ren Echo
  • 创建于 : 2026-06-15 09:30:00
  • 更新于 : 2026-06-27 10:06:11
  • 链接: https://renecho-blog.pages.dev/2026/06/15/2026-06-15-kage-offline-website-mirror/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论