kage:用「渲染快照 + 剥离 JS」解决网页离线存档的终极痛点
核心观点
浏览器的「另存为」坏掉了十几年,根本原因从未被正面解决——它保存的是 HTML 源码,而现代网页的实际内容存在于 JavaScript 执行后的 DOM 里。kage 换了一条路:驱动真实的 headless Chrome 把页面跑完,抓下渲染结果,然后把所有脚本连根拔掉,只留下 HTML + CSS + 图片 + 字体的本地镜像。这不是修补「另存为」,而是从根本上替换它。
技术机制:关键巧妙之处
kage 的核心不在于爬虫本身,而在于渲染与剥离的时序:先让 Chrome 把所有 JS 都跑完(包括异步请求、懒加载、SPA 路由),DOM 稳定后再截取这个「人眼能看见的快照」,然后才做资源本地化和脚本清除。
这个顺序至关重要——传统爬虫(wget、HTTrack)在 JS 执行之前就截走 HTML,所以 React/Vue 渲染出来的内容一片空白。kage 的方案使得即使是动态生成的文章内容、懒加载的图片,都能被完整捕获。
工作流四步走:
# 第一步:克隆整站(宽度优先爬取,遵守 robots.txt) kage clone paulgraham.com --max-pages 50 --scroll # 第二步:本地预览 kage serve $HOME/data/kage/paulgraham.com # → http://127.0.0.1:8800 # 第三步:打包为 ZIM 归档(开放格式,Kiwix 生态通用) kage pack paulgraham.com # → paulgraham.com.zim # 第四步:打包为自包含可执行文件(无需任何依赖) kage pack paulgraham.com --format binary -o paulgraham ./paulgraham # 直接运行,自带服务幂等性设计值得单独一提:同一篇文章无论通过 http/https、有无 trailing slash 被抓到,都写入同一个文件,Ctrl-C 中断后重启会断点续传,--refresh增量更新,--force全量重建。这让 kage 可以被放进定期任务里,像订阅一样持续维护镜像。
历史对比:比前辈强在哪,牺牲了什么
| 工具 | 机制 | JS 渲染 | 整站爬取 | 离线可用 |
|---|---|---|---|---|
| 浏览器「另存为」 | 截 HTML 源码 | ❌ | ❌ | 经常空白 |
| wget -mpk | 递归下载静态资源 | ❌ | ✅ | SPA 失败 |
| HTTrack | 同 wget 类路线 | ❌ | ✅ | 同上 |
| SingleFile(浏览器扩展) | 截渲染后 DOM | ✅ | ❌ 单页 | ✅ |
| kage | headless Chrome 渲染 + 剥 JS | ✅ | ✅ | ✅ |
代价是清晰的:交互功能完全丢失。删掉脚本意味着登录、评论、站内搜索、表单、地图全部失效。kage 存下来的是「阅读态」而非「使用态」——这是有意为之的取舍,而不是缺陷。ZIM 格式的另一个已知限制是不带全文搜索索引(Kiwix 官方内容包有,kage 生成的没有),这让大型归档站内检索变得不便。
关键特性速览
打包格式三选一:
.zim:开放格式,Kiwix 生态完全兼容,可在手机/桌面/服务器跨平台读取,不绑定 kage,十年后仍可开binary:约 13 MB 基础体积 + 站点内容,无需任何安装,跨系统分发(从 Mac 打包一个 Windows.exe完全可行)--app:macOS 生成.appbundle,Linux 生成 AppImage,Windows 生成无控制台 GUI 程序,双击即打开站点
爬取控制参数(实用优先):
--max-pages 50 # 只抓 50 页,快速预览 --max-depth 2 # 只跟进两层链接 --scope-prefix /doc # 只爬 /doc 路径下的内容 --subdomains # 把子域名也纳入范围 --scroll # 自动滚动,触发懒加载图片 --workers 4 # 并发渲染页数(默认4) --crawl-delay 0s # 覆写 robots.txt 的 Crawl-delay交叉验证
信源一:ic.work 技术资讯(《Kage 开源:把动态网站渲染成无脚本离线包》,2025年6月15日)
该文独立评价了 kage 的核心机制,与原文观点高度一致,并补充了一个有价值的框架性判断:「你要保存的是『内容』还是『功能』?」这个问题比原文更精炼地划定了 kage 的适用边界。该文同样指出 ZIM 无全文搜索索引的限制,且对「跨平台分发」打了一个折扣——自包含可执行文件仍需对应架构的基础二进制,并非真正万能单文件。与原文叙述一致,无明显反驳。
信源二:h3blog 评测文章(《超1000星!13MB打包整个网站、剥离所有JS,这个Go工具刷爆HN》,2025年6月16日)
该文提供了社区反应数据:kage 在 Hacker News 获得 609 分、119 条讨论,不到 24 小时破千星,说明它触及的是开发者社区真实存在的长期痛点。更重要的是,该文作者坦率指出:对 Twitter、Notion、Figma 这类重度 SPA,kage 原理上就「不太行」——因为删掉 JS 之后交互逻辑消失,残留的 DOM 快照几乎没有可读价值。这是原文 GitHub README 里未充分强调的边界,是对原文的有效补充而非反驳。
综合判断:两个独立信源与原文核心立场吻合,但共同在「重度 JS SPA 场景」和「ZIM 搜索索引缺失」两点上提供了原文刻意淡化的局限,读者需留意。
个人启发
对开发者 / 技术用户的直接动作建议:
立刻可做的:把你长期依赖的文档站(Go 官方文档、MDN、某个即将下线的开源项目文档)用
kage clone --scope-prefix /docs做一份镜像。成本极低,ZIM 格式保证十年后仍可读。判断使用场景:如果你要归档的是博客、文档、新闻、Wikipedia 镜像——kage 是目前最省力的方案;如果你要「复制功能」(让一个 Web App 离线可用),kage 解决不了这个问题,那是 PWA / Service Worker 的领域。
分发场景:给非技术背景的人分享技术资料,
--format binary --app打出一个双击即开的应用,比发一堆 HTML 文件夹靠谱得多。Docker 优先:在 CI/CD 或服务器上定期归档,用容器镜像跳过 Chrome 安装环境配置问题,是最干净的用法。
延伸思考
「渲染后快照」会成为新的存档标准吗?Wayback Machine 目前存的是 HTTP 原始响应(源码),无法复现 SPA 渲染结果。如果 kage 这套思路被互联网档案馆这类机构采纳,数字保存领域会迎来一次范式迁移——但随之而来的是存储成本骤增(渲染比抓取慢 10-100 倍),这个矛盾如何解决值得关注。
剥离 JS 的「安全归档」属性有多大价值?kage 存下来的文件不会「回拨」任何网络请求,这让它天然成为一种隔离阅读方案——用于审计可疑页面、保存证据材料、或者在敏感环境中分发受信内容都有潜力,这个维度原文几乎没有提及,但可能是其隐藏的高价值场景。
ZIM 生态的冷门价值:Kiwix 已经把 Wikipedia 全库、Stack Overflow、Project Gutenberg 打包成 ZIM 分发给无网络地区的学校。kage 让普通用户也能生产 ZIM 文件,这意味着「个人知识归档 → ZIM → Kiwix 生态分发」这条链路首次变得平民化——技术内容创作者是否会开始提供官方 ZIM 下载,是一个值得观察的趋势。
📚 参考来源
- GitHub - tamnd/kage: Shadow any website for offline viewing, with the JavaScript stripped out · GitHub