Files
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

291 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- WEHUB_ZH_README -->
> [!NOTE]
> 本文档由 WeHub 基于上游 README 翻译整理,属于社区翻译,非官方中文文档。
> [English](./README.en.md) · [原始项目](https://gitea-dev.autobee.pro/frostbyte_neo/kage) · [上游 README](https://gitea-dev.autobee.pro/frostbyte_neo/kage/blob/HEAD/README.md)
> 原作者、版权与许可证归属以原始项目及本仓库 LICENSE 文件为准。
# kage
[![ci](https://github.com/tamnd/kage/actions/workflows/ci.yml/badge.svg)](https://github.com/tamnd/kage/actions/workflows/ci.yml)
[![Release](https://img.shields.io/github/v/release/tamnd/kage)](https://github.com/tamnd/kage/releases/latest)
[![Go Reference](https://pkg.go.dev/badge/github.com/tamnd/kage.svg)](https://pkg.go.dev/github.com/tamnd/kage)
[![Go Report Card](https://goreportcard.com/badge/github.com/tamnd/kage)](https://goreportcard.com/report/github.com/tamnd/kage)
[![License](https://img.shields.io/github/license/tamnd/kage)](./LICENSE)
**kage**(影,"shadow")会将网站克隆到一个可离线浏览的文件夹中,并剔除所有脚本。它会在真实的无头 Chromeheadless Chrome)中打开每个页面,等待页面稳定后,快照人类所见到的 DOM,然后删除所有 JavaScript,并将 CSS、图片和字体下载到本地路径。最终落盘的内容看起来与线上站点一致,且不会执行任何代码。
[安装](#install) • [快速开始](#quick-start) • [命令](#commands) • [克隆](#clone) • [打包](#pack-it-into-one-file) • [双击应用](#a-double-click-app) • [原生窗口](#a-real-window-not-a-browser-tab) • [工作原理](#how-it-works)
![kage 克隆 paulgraham.com、打包为单个文件并离线提供访问的演示](docs/static/demo.gif)
你早已熟悉这个问题。你对想保存的页面点击「另存为」,六个月后打开却发现一片空白、转圈不停,或者副本仍在尝试连接早已不存在的分析服务器。这页面从未真正属于你。它只是别人 JavaScript 的瘦客户端。
kage 走了另一条路。它驱动真实浏览器,让页面完成该做的一切,抓取最终结果,然后从中剥离所有脚本。无追踪、无网络调用、无意外。只有 `.html` 文件,你可以直接从磁盘打开、交给朋友,或打包成单个文件后十年都不用管。
完整文档与指南见 **[kage.tamnd.com](https://kage.tamnd.com)**.
## 安装
```bash
go install github.com/tamnd/kage/cmd/kage@latest
```
更喜欢预编译二进制?可从 [releases](https://github.com/tamnd/kage/releases). 获取压缩包、`.deb`/`.rpm`/`.apk` 或校验和。也可以交给包管理器:
```bash
# 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 的容器镜像:
```bash
docker run --rm -v "$PWD/out:/out" ghcr.io/tamnd/kage clone paulgraham.com
```
kage 驱动真实浏览器,因此主机上需要 Chrome 或 Chromium。它会自动查找系统安装;也可用 `--chrome``KAGE_CHROME` 环境变量指向特定路径。容器无需额外配置。
Shell 补全已内置:`kage completion bash|zsh|fish|powershell`
## 快速开始
我们来镜像 Paul Graham 的文章,这样你可以在飞机上、没有 Wi-Fi 的笔记本上,或在站点终于改版后的 2050 年阅读它们:
```bash
# 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
```
这就是完整流程。每篇文章、每张图片、每份样式表,都冻结在你的磁盘上,零网络即可运行。接下来两步可选但很方便:将整个镜像折叠成单个文件,并在独立窗口中打开。
```bash
# 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 的离线阅读服务 |
## 克隆
```bash
# 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.txt`Crawl-delay` 为页面启动间隔 |
| `-f, --force` | `false` | 先删除该主机已有的镜像 |
| `--chrome` | | Chrome/Chromium 二进制文件路径 |
`kage clone --help` 包含其余选项,包括渲染时序、并发与资源大小调节。
### 提供访问
`kage serve` 会在已克隆文件夹上运行轻量静态文件服务器,使链接与资源像真实主机上一样解析:
```bash
kage serve $HOME/data/kage/paulgraham.com
# open http://127.0.0.1:8800
```
## 打包成单个文件
镜像是文件夹,便于浏览,却不便于搬运。复制成千上万个小文件很慢,「给你这个目录」也不是好送的礼物。`kage pack` 将整个镜像折叠为一个制品,形状由你选择:开放的 ZIM 归档,或本身就是站点的单个可执行文件。
### 单个 ZIM 文件
```bash
kage pack paulgraham.com # -> paulgraham.com.zim
kage open paulgraham.com.zim
```
ZIM 是专为此而生的开放文件格式:将整个网站(或整本维基百科)压缩、索引后塞进一个只读文件。kage 将整个镜像写入其中,文本经 zstd 压缩,媒体原样存储。它是 [Kiwix](https://kiwix.org), 背后的格式——人们用这一离线内容项目把维基百科、Stack Overflow 和 Project Gutenberg 带上船、带进没有互联网的教室、装进手机度过长途飞行。由于该格式是 documented standard(有文档的标准),而非 kage 的发明,你今天制作的 `paulgraham.com.zim` 多年后仍可在任何 ZIM 阅读器中打开。
所以你并不被锁定在 kage 上。`kage open` 是重新接入的最快方式,但同一个文件也适用于更广泛的 Kiwix 生态系统:
```bash
kage open paulgraham.com.zim # read it back with kage
kiwix-serve paulgraham.com.zim # or serve it with Kiwix at http://localhost
```
你也可以在 [Kiwix 桌面应用](https://kiwix.org/en/applications/), 中双击该文件,或在 [Android 或 iOS 版 Kiwix](https://kiwix.org/en/applications/) 上加载它,在手机上阅读你的镜像。有一点需要注意:kage 会写入结构合法、带有标准元数据的归档文件,但不会构建 Kiwix 官方包自带的全文搜索索引,因此浏览和点击在各处都能正常工作,但阅读器内的搜索功能会受限。
打包是确定性的。同一镜像始终会生成字节级完全相同的文件,归档 UUID 由内容派生而非随机生成,因此包可以安全地进行校验和与缓存。裸主机名会相对于默认输出目录解析,因此 `kage pack paulgraham.com``kage clone paulgraham.com` 之后就能直接使用。
### 自包含二进制文件
`--format binary` 将归档粘接到 kage 的副本上,生成单个可执行文件,运行后即可离线提供该站点。你把它发给任何人都无需安装任何东西:不需要 kage,不需要 ZIM 阅读器,什么都不需要。
```bash
kage pack paulgraham.com --format binary -o paulgraham
./paulgraham
```
附加的归档与平台无关;只有基础可执行文件携带架构信息。默认情况下 kage 会追加到自身,因此你会得到适用于运行它的那台机器的查看器。将 `--base` 指向为其他操作系统构建的 kage(从 [release](https://github.com/tamnd/kage/releases); 获取,每个平台都会提供)即可在你自己的机器上生成适用于该平台的查看器。kage 会读取基础可执行文件的头部以确定目标平台,因此 Windows 查看器会自动获得 `.exe` 名称:
```bash
# 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` 包:
```bash
kage pack paulgraham.com --app # -> paulgraham.app
open paulgraham.app # or double-click it in Finder
```
在 Linux 上,将 `--base` 指向 Linux 版 kage,你会得到一个带 `.desktop` 启动器(`Terminal=false`,因此没有控制台)的 [AppImage](https://appimage.org)-style `.AppDir`。如果已安装 [`appimagetool`](https://github.com/AppImage/appimagetool),kage 会将其合并为单个可双击的 `.AppImage`
```bash
kage pack paulgraham.com --app --base kage-linux-amd64 # -> paulgraham.AppDir (+ .AppImage)
```
kage 会从镜像中提取 favicon 来查找图标(优先使用较大的 `apple-touch-icon.png`,否则回退到 `favicon.ico`);传入 `--icon some.png` 可覆盖它。将 `--app``webview` 基础(见下文)配合使用,双击会打开原生窗口而非浏览器,这才是完整的「像一个应用」效果。
Windows 不需要打包,因为单个 `.exe` 本身就是应用。问题在于控制台窗口。发布版提供了一个 `kage_<version>_windows-gui_<arch>.zip`,其二进制链接到 GUI 子系统,因此打包在其上的查看器打开时背后不会出现控制台:
```bash
# 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](docs/static/webview.png)
```bash
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` 沿用同一思路:镜像中的链接已经是镜像相对路径,这些路径与归档内容条目一一对应,因此在已提供服务的页面中点击会直接命中正确的条目,完全无需重写。
## 从源码构建
```bash
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 签名:
```bash
git tag v0.1.1
git push --tags
```
镜像标签不带 `v` 前缀(`ghcr.io/tamnd/kage:0.1.1`)。Homebrew 和 Scoop 步骤会在其 token 存在之前自动禁用,因此首次发布无需额外密钥即可工作。
## 许可证
MIT。参见 [LICENSE](LICENSE)。