kage:用 headless Chrome 抓站,剥掉 JS 后打包成 ZIM 或单个可执行文件
kage(影,shadow)把网站克隆到一个可以离线浏览的目录里,页面中的脚本被全部剥离。它用真实的 headless Chrome 打开每个页面,等页面稳定,快照人类会看到的那个 DOM,然后删除所有 JavaScript,把 CSS、图片、字体拉到本地路径。落到磁盘上的结果看起来像原站,但不运行任何代码。
仓库:https://github.com/tamnd/kage
文档:https://kage.tamnd.com
它针对的是这种场景:对一个页面「另存为」,半年后打开发现白屏、转圈,或者副本还在向一个早就不存在的统计服务器回连。kage 驱动真实浏览器,让页面跑完,取走最终结果,再把脚本全部撕掉。没有追踪,没有网络请求,只有能直接从磁盘打开的 .html,可以递给别人,也可以打包成单个文件。
安装
go install github.com/tamnd/kage/cmd/kage@latest
预编译二进制见 releases。包管理器:
- Homebrew(macOS):
brew install --cask tamnd/tap/kage - Scoop(Windows):
scoop bucket add tamnd https://github.com/tamnd/scoop-bucket,然后scoop install kage - apt(Debian/Ubuntu)与 dnf(Fedora/RHEL):走 tamnd.github.io/linux-repo
自带 Chromium 的容器镜像:
docker run --rm -v "$PWD/out:/out" ghcr.io/tamnd/kage clone paulgraham.com
kage 要驱动真实浏览器,宿主机上得有 Chrome/Chromium:它会找系统安装,也可以用 --chrome 或环境变量 KAGE_CHROME 指定。容器镜像不需要额外准备。附带 shell 补全。
四条命令
kage clone paulgraham.com # 镜像到 $HOME/data/kage/paulgraham.com/
kage serve $HOME/data/kage/paulgraham.com # 离线阅读,http://127.0.0.1:8800
kage pack paulgraham.com # -> paulgraham.com.zim
kage open paulgraham.com.zim
kage pack paulgraham.com --format binary -o paulgraham
./paulgraham # 自己提供服务,不依赖任何安装
| 命令 | 作用 |
|---|---|
kage clone | 用 headless Chrome 渲染站点,写出可浏览、无脚本的镜像 |
kage serve [dir] | 用本地 HTTP 服务预览克隆目录 |
kage pack | 把镜像折叠成一个 ZIM 归档、一个自包含阅读器二进制,或一个双击应用 |
kage open | 把打包好的 ZIM 重新提供服务,离线阅读 |
clone:广度优先爬取、断点续爬与幂等
kage clone https://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
kage clone paulgraham.com --refresh
一次克隆是礼貌的广度优先爬取:读 robots.txt,从 sitemap.xml 取种子,除非另有说明否则停留在种子主机上。幂等性以「写出的文件」为键——同一篇文章的 http/https、带或不带尾斜杠,只会抓一次。Ctrl-C 会保存进度,再跑一次即从中断处继续。--refresh 原地重渲染,--force 清掉该主机目录从头开始。
相关 flag:-o/--out(默认 $HOME/data/kage)、-p/--max-pages(0 表示不限)、-d/--max-depth(0 表示不限)、--scope-prefix、--subdomains、--exclude、--scroll、--workers(默认 4)、--no-robots、--crawl-delay、-f/--force、--chrome。
serve 就是把镜像目录挂到本地 HTTP:
kage serve $HOME/data/kage/paulgraham.com
# 打开 http://127.0.0.1:8800
pack 的三种形态:ZIM、自包含二进制、双击应用
单个 ZIM 文件
kage pack paulgraham.com # -> paulgraham.com.zim
kage open paulgraham.com.zim
ZIM 是用于把整个网站(或整个 Wikipedia)装进一个压缩、带索引、只读文件的开放格式,也是 Kiwix 背后的格式,Wikipedia、Stack Overflow、Project Gutenberg 的离线版本都用它。kage 对文本做 zstd 压缩,媒体原样存储。因为它是文档化的标准,今天生成的 .zim 几年后在任何 ZIM 阅读器里仍能打开:
kiwix-serve paulgraham.com.zim
需要注意:kage 写出的是结构合法、元数据标准的归档,但不构建 Kiwix 官方包附带的那种全文搜索索引;浏览和点击在各处都正常,阅读器内搜索能力有限。打包是确定性的:同一份镜像产出逐字节相同的文件,归档 UUID 由内容派生。裸主机名会按默认输出目录解析。
自包含二进制
kage pack paulgraham.com --format binary -o paulgraham
./paulgraham
附加进可执行文件的归档与平台无关,只有基础可执行文件携带架构信息。把 --base 指向为另一个操作系统构建的 kage,就能产出对应平台的阅读器:
kage pack paulgraham.com --format binary --base kage-windows-amd64.exe # -> paulgraham.exe
二进制里带着一整个 kage,所以体积约为 13 MiB 再加上站点本身。只要内容的话,ZIM 小得多。
双击应用
--app 把阅读器包装成桌面应用(macOS 是 .app bundle;Linux 用 appimagetool 出 AppImage;Windows 不需要 bundle,但要用 windows-gui zip 得到无控制台的 .exe)。
kage pack paulgraham.com --app
open paulgraham.app
图标从镜像的 favicon 里挖出来(优先 apple-touch-icon.png,回退 favicon.ico),用 --icon 覆盖。
独立窗口:需要 cgo 的 webview 构建
默认情况下,打包出的二进制打开系统浏览器。带 webview tag 构建 kage,则会通过操作系统的 WebView 打开自己的窗口(macOS 是 WKWebView,Windows 是 WebView2,Linux 是 WebKitGTK):
make build-webview # 或者:CGO_ENABLED=1 go build -tags webview ./cmd/kage
kage pack paulgraham.com --format binary --base bin/kage -o paulgraham
./paulgraham
这个构建需要 cgo 并链接平台 WebView,所以保持可选。默认构建是纯 Go(CGO_ENABLED=0),预编译发行版二进制打开浏览器。
实现与目录结构
seed URL -> headless Chrome -> final DOM -> strip JS -> localise assets -> disk
一组 Chrome 标签页负责渲染页面,另一个池子用普通 HTTP 抓资源。每个 URL 确定性地映射到本地路径,因此链接在它指向的资源下载完成之前就能被改写。输出布局:
paulgraham.com/
├── index.html
├── greatwork.html
├── _kage/ # 保留目录:资源与爬取状态
│ ├── paulgraham.com/site.css
│ ├── paulgraham.com/pg.png
│ └── state.json
仓库结构:cmd/kage/(薄 main)、cli/(cobra 命令树)、clone/(frontier、渲染 worker、资源 worker、断点状态)、browser/(headless Chrome 控制与 DOM 快照)、sanitize/(剥离脚本、事件处理器、javascript: URL)、asset/(下载并本地化 CSS/图片/字体)、urlx/(确定性的 URL 到路径映射)、zim/(纯 Go 的 ZIM 读写)、pack/(镜像转 ZIM 或自包含二进制)、viewer/。
从源码构建:
git clone https://github.com/tamnd/kage
cd kage
make build # -> bin/kage(纯 Go,打开浏览器)
make build-webview # 原生窗口阅读器(需要 cgo)
make test
发布流程:推一个版本 tag,GitHub Actions 跑 GoReleaser(归档包、.deb/.rpm/.apk、带 Chromium 的多架构 GHCR 镜像、checksums、SBOM、cosign 签名)。
License: MIT。