wehub-resource-sync c0ecd55c48
ci / test (macos-latest) (push) Has been cancelled
ci / test (ubuntu-latest) (push) Has been cancelled
ci / lint (push) Has been cancelled
ci / govulncheck (push) Has been cancelled
ci / tidy (push) Has been cancelled
ci / webview (push) Has been cancelled
ci / windows-gui (push) Has been cancelled
release / check (push) Has been cancelled
release / release (push) Has been cancelled
docs: make Chinese README the default
2026-07-14 02:25:43 +00:00

Note

本文档由 WeHub 基于上游 README 翻译整理,属于社区翻译,非官方中文文档。
English · 原始项目 · 上游 README
原作者、版权与许可证归属以原始项目及本仓库 LICENSE 文件为准。

kage

ci Release Go Reference Go Report Card License

kage(影,"shadow")会将网站克隆到一个可离线浏览的文件夹中,并剔除所有脚本。它会在真实的无头 Chromeheadless Chrome)中打开每个页面,等待页面稳定后,快照人类所见到的 DOM,然后删除所有 JavaScript,并将 CSS、图片和字体下载到本地路径。最终落盘的内容看起来与线上站点一致,且不会执行任何代码。

安装快速开始命令克隆打包双击应用原生窗口工作原理

kage 克隆 paulgraham.com、打包为单个文件并离线提供访问的演示

你早已熟悉这个问题。你对想保存的页面点击「另存为」,六个月后打开却发现一片空白、转圈不停,或者副本仍在尝试连接早已不存在的分析服务器。这页面从未真正属于你。它只是别人 JavaScript 的瘦客户端。

kage 走了另一条路。它驱动真实浏览器,让页面完成该做的一切,抓取最终结果,然后从中剥离所有脚本。无追踪、无网络调用、无意外。只有 .html 文件,你可以直接从磁盘打开、交给朋友,或打包成单个文件后十年都不用管。

完整文档与指南见 kage.tamnd.com.

安装

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

更喜欢预编译二进制?可从 releases. 获取压缩包、.deb/.rpm/.apk 或校验和。也可以交给包管理器:

# 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)
curl -fsSL https://tamnd.github.io/linux-repo/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/tamnd.gpg
echo "deb [signed-by=/usr/share/keyrings/tamnd.gpg] https://tamnd.github.io/linux-repo/apt stable main" | sudo tee /etc/apt/sources.list.d/tamnd.list
sudo apt update && sudo apt install kage

# dnf (Fedora, RHEL)
sudo dnf config-manager --add-repo https://tamnd.github.io/linux-repo/dnf/tamnd.repo
sudo dnf install kage

或者不必自行安装 Chrome,使用捆绑了 Chromium 的容器镜像:

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

kage 驱动真实浏览器,因此主机上需要 Chrome 或 Chromium。它会自动查找系统安装;也可用 --chromeKAGE_CHROME 环境变量指向特定路径。容器无需额外配置。

Shell 补全已内置:kage completion bash|zsh|fish|powershell

快速开始

我们来镜像 Paul Graham 的文章,这样你可以在飞机上、没有 Wi-Fi 的笔记本上,或在站点终于改版后的 2050 年阅读它们:

# 1. Clone the site into $HOME/data/kage/paulgraham.com/
kage clone paulgraham.com

# 2. Read it back offline in your browser
kage serve $HOME/data/kage/paulgraham.com
# open http://127.0.0.1:8800

这就是完整流程。每篇文章、每张图片、每份样式表,都冻结在你的磁盘上,零网络即可运行。接下来两步可选但很方便:将整个镜像折叠成单个文件,并在独立窗口中打开。

# 3. Squeeze the mirror into a single shareable file
kage pack paulgraham.com               # -> paulgraham.com.zim
kage open paulgraham.com.zim

# 4. Or into one executable that *is* the site
kage pack paulgraham.com --format binary -o paulgraham
./paulgraham                           # serves itself, needs nothing installed

命令

命令 作用
kage clone <url> 在无头 Chrome 中渲染站点,并写入可浏览、无脚本的镜像
kage serve [dir] 通过本地 HTTP 服务器预览已克隆的文件夹
kage pack <mirror-dir> 将镜像折叠为单个 ZIM 归档、自包含查看器二进制文件或双击应用
kage open <file.zim> 提供已打包 ZIM 的离线阅读服务

克隆

# The whole site, into $HOME/data/kage/<host>/
kage clone https://paulgraham.com

# Just the first 50 pages, two links deep, for a quick taste
kage clone paulgraham.com --max-pages 50 --max-depth 2

# Only one section of a bigger site
kage clone go.dev --scope-prefix /doc

# Pull in subdomains too, and scroll each page to trip lazy-loaded images
kage clone example.com --subdomains --scroll

# Come back next month and re-render in place to catch new essays
kage clone paulgraham.com --refresh

克隆是一次礼貌的广度优先爬取。它读取 robots.txt,从 sitemap.xml 播种,除非你另行指定,否则始终停留在种子主机上。它还固执地保持幂等:每个页面以其写入的文件为键,因此同一篇文章无论通过 http 还是 https 访问、有无尾部斜杠,都只会抓取一次。按 Ctrl-C 会在退出时保存进度;再次运行会从停止处继续。--refresh 会原地重新渲染,--force 会清除该主机并从头开始。

你实际会用到的标志:

标志 默认值 含义
-o, --out $HOME/data/kage 输出根目录;镜像落在 <out>/<host>/
-p, --max-pages 0 抓取 N 页后停止(0 = 无限制)
-d, --max-depth 0 跟随链接的深度(0 = 无限制)
--scope-prefix 仅爬取以此前缀开头的路径
--subdomains false 将种子主机的子域视为在范围内
--exclude 要跳过的路径前缀(可重复)
--scroll false 自动滚动每页以触发懒加载
--workers 4 同时渲染的页面数
--no-robots false 忽略 robots.txt(礼貌爬取)
--crawl-delay 0s 覆盖 robots.txtCrawl-delay 为页面启动间隔
-f, --force false 先删除该主机已有的镜像
--chrome Chrome/Chromium 二进制文件路径

kage clone --help 包含其余选项,包括渲染时序、并发与资源大小调节。

提供访问

kage serve 会在已克隆文件夹上运行轻量静态文件服务器,使链接与资源像真实主机上一样解析:

kage serve $HOME/data/kage/paulgraham.com
# open http://127.0.0.1:8800

打包成单个文件

镜像是文件夹,便于浏览,却不便于搬运。复制成千上万个小文件很慢,「给你这个目录」也不是好送的礼物。kage pack 将整个镜像折叠为一个制品,形状由你选择:开放的 ZIM 归档,或本身就是站点的单个可执行文件。

单个 ZIM 文件

kage pack paulgraham.com               # -> paulgraham.com.zim
kage open paulgraham.com.zim

ZIM 是专为此而生的开放文件格式:将整个网站(或整本维基百科)压缩、索引后塞进一个只读文件。kage 将整个镜像写入其中,文本经 zstd 压缩,媒体原样存储。它是 Kiwix, 背后的格式——人们用这一离线内容项目把维基百科、Stack Overflow 和 Project Gutenberg 带上船、带进没有互联网的教室、装进手机度过长途飞行。由于该格式是 documented standard(有文档的标准),而非 kage 的发明,你今天制作的 paulgraham.com.zim 多年后仍可在任何 ZIM 阅读器中打开。

所以你并不被锁定在 kage 上。kage open 是重新接入的最快方式,但同一个文件也适用于更广泛的 Kiwix 生态系统:

kage open paulgraham.com.zim            # read it back with kage
kiwix-serve paulgraham.com.zim          # or serve it with Kiwix at http://localhost

你也可以在 Kiwix 桌面应用, 中双击该文件,或在 Android 或 iOS 版 Kiwix 上加载它,在手机上阅读你的镜像。有一点需要注意:kage 会写入结构合法、带有标准元数据的归档文件,但不会构建 Kiwix 官方包自带的全文搜索索引,因此浏览和点击在各处都能正常工作,但阅读器内的搜索功能会受限。

打包是确定性的。同一镜像始终会生成字节级完全相同的文件,归档 UUID 由内容派生而非随机生成,因此包可以安全地进行校验和与缓存。裸主机名会相对于默认输出目录解析,因此 kage pack paulgraham.comkage clone paulgraham.com 之后就能直接使用。

自包含二进制文件

--format binary 将归档粘接到 kage 的副本上,生成单个可执行文件,运行后即可离线提供该站点。你把它发给任何人都无需安装任何东西:不需要 kage,不需要 ZIM 阅读器,什么都不需要。

kage pack paulgraham.com --format binary -o paulgraham
./paulgraham

附加的归档与平台无关;只有基础可执行文件携带架构信息。默认情况下 kage 会追加到自身,因此你会得到适用于运行它的那台机器的查看器。将 --base 指向为其他操作系统构建的 kage(从 release; 获取,每个平台都会提供)即可在你自己的机器上生成适用于该平台的查看器。kage 会读取基础可执行文件的头部以确定目标平台,因此 Windows 查看器会自动获得 .exe 名称:

# Sitting on a Mac, build a Windows viewer
kage pack paulgraham.com --format binary --base kage-windows-amd64.exe   # -> paulgraham.exe

代价是体积。该二进制文件包含完整的 kage,因此无论镜像多小,体积都约为 13 MiB 加上站点内容。如果你只需要内容,ZIM 要精简得多。

双击即可运行的应用

裸二进制文件在终端中很好用,但在文件管理器中双击时体验不佳:macOS 会在站点后面打开一个 Terminal 窗口,Windows 则会在旁边闪现一个控制台。添加 --app,kage 会将同一查看器封装为正规的桌面应用,双击即可打开站点,无需终端,并使用镜像自身的 favicon 作为图标。

在 macOS 上你会得到一个真正的 .app 包:

kage pack paulgraham.com --app                 # -> paulgraham.app
open paulgraham.app                            # or double-click it in Finder

在 Linux 上,将 --base 指向 Linux 版 kage,你会得到一个带 .desktop 启动器(Terminal=false,因此没有控制台)的 AppImage-style .AppDir。如果已安装 appimagetoolkage 会将其合并为单个可双击的 .AppImage

kage pack paulgraham.com --app --base kage-linux-amd64   # -> paulgraham.AppDir (+ .AppImage)

kage 会从镜像中提取 favicon 来查找图标(优先使用较大的 apple-touch-icon.png,否则回退到 favicon.ico);传入 --icon some.png 可覆盖它。将 --appwebview 基础(见下文)配合使用,双击会打开原生窗口而非浏览器,这才是完整的「像一个应用」效果。

Windows 不需要打包,因为单个 .exe 本身就是应用。问题在于控制台窗口。发布版提供了一个 kage_<version>_windows-gui_<arch>.zip,其二进制链接到 GUI 子系统,因此打包在其上的查看器打开时背后不会出现控制台:

# Build a console-free Windows viewer (from any OS)
kage pack paulgraham.com --format binary --base kage-windows-gui-amd64.exe   # -> paulgraham.exe

真正的窗口,而非浏览器标签页

默认情况下,打包后的二进制文件会打开系统浏览器,这意味着站点会作为又一个标签页出现,地址栏一应俱全,挤在你已经打开的 47 个标签旁边。使用 webview 标签构建 kage,它会在自己的窗口中打开站点,底层使用操作系统的 WebViewmacOS 上为 WKWebViewWindows 上为 WebView2Linux 上为 WebKitGTK)。Paul Graham 的文章,离线阅读,放在一个看起来、用起来都像真正应用的东西里:

在原生 kage 窗口中离线提供 paulgraham.com

make build-webview                       # or: CGO_ENABLED=1 go build -tags webview ./cmd/kage
kage pack paulgraham.com --format binary --base bin/kage -o paulgraham
./paulgraham                             # opens a window, no browser in sight

此构建需要 cgo 并链接平台 WebView,因此仍为可选。默认构建为纯 Go(CGO_ENABLED=0),预构建的发布二进制文件会打开浏览器,这使交叉编译的发布保持简单。kage open 遵循同一标签,因此使用 -tags webview 构建时,也会在原生窗口中显示 ZIM。

工作原理

seed URL ─▶ headless Chrome ─▶ final DOM ─▶ strip JS ─▶ localise assets ─▶ disk
              (render)          (snapshot)   (sanitize)   (rewrite links)

一组 Chrome 标签页负责渲染页面;另一组通过纯 HTTP 获取资源。每个 URL 都会确定性地映射到本地路径,因此在它们指向的资源下载完成之前,链接就已经被重写。输出如下所示:

paulgraham.com/
├── index.html                  # the home page, scripts stripped
├── greatwork.html              # /greatwork.html, an essay
├── _kage/                      # reserved: assets and crawl state
│   ├── paulgraham.com/site.css  # localised stylesheet (url() rewritten)
│   ├── paulgraham.com/pg.png
│   └── state.json              # visited set, for resuming
└── ...

pack 沿用同一思路:镜像中的链接已经是镜像相对路径,这些路径与归档内容条目一一对应,因此在已提供服务的页面中点击会直接命中正确的条目,完全无需重写。

从源码构建

git clone https://github.com/tamnd/kage
cd kage
make build          # -> bin/kage (pure Go, opens the browser)
make build-webview  # -> bin/kage with the native-window viewer (needs cgo)
make test           # full suite, including the Chrome-driven end-to-end tests
make test-short     # skip the tests that launch a browser

仓库按职责划分:

cmd/kage/   thin main: pins the main thread, then hands off to cli.Execute
cli/        the cobra command tree and flag wiring
clone/      the crawl: frontier, render workers, asset workers, resume state
browser/    headless Chrome control and DOM snapshotting
sanitize/   strip scripts, handlers, and javascript: URLs from the DOM
asset/      download and localise CSS, images, and fonts
urlx/       the deterministic URL-to-path mapping
zim/        a pure-Go ZIM reader and writer
pack/       mirror to ZIM or self-contained binary, and the offline HTTP handler
viewer/     present a served site: system browser, or native window (webview tag)
docs/       the tago documentation site

发布

推送版本标签后,GitHub Actions 会运行 GoReleaser,构建归档文件、.deb/.rpm/.apk 包、捆绑 Chromium 的多架构 GHCR 镜像、校验和、SBOM 以及 cosign 签名:

git tag v0.1.1
git push --tags

镜像标签不带 v 前缀(ghcr.io/tamnd/kage:0.1.1)。Homebrew 和 Scoop 步骤会在其 token 存在之前自动禁用,因此首次发布无需额外密钥即可工作。

许可证

MIT。参见 LICENSE

S
Description
把网站打包为可离线浏览目录、ZIM 文件或独立应用的 Go 工具
Readme MIT 1.1 MiB
Languages
Go 97.4%
Python 1.5%
Dockerfile 0.7%
Makefile 0.4%