news 2026/9/27 3:03:59

为什么浏览器“另存为“总是失败?kage“先渲染、再剥离、后本地化“三阶段原理全解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
为什么浏览器“另存为“总是失败?kage“先渲染、再剥离、后本地化“三阶段原理全解

为什么浏览器"另存为"总是失败?kage"先渲染、再剥离、后本地化"三阶段原理全解

【免费下载链接】kageShadow any website for offline viewing, with the JavaScript stripped out项目地址: https://gitcode.com/gh_mirrors/kage6/kage

你有没有这样的经历:想永久保存一篇文章,点了浏览器"另存为网页",半年后打开却只剩一片空白或永远转圈的加载图标。kage 就是为解决这个问题而生的开源离线存档工具:它克隆网站供离线浏览,并把所有 JavaScript 剥离干净。本文将拆解 kage "先渲染、再剥离、后本地化"的三阶段原理,帮你一次看懂它为什么比"另存为"可靠得多。

浏览器"另存为"到底败在哪?

问题不在"存",而在"存错了东西"。现代网页早就不是静态文档,而是一个靠 JavaScript 实时生成的应用,"另存为"通常会在三个地方翻车:

失败模式表现根本原因
空白页打开后只剩骨架保存的是"图纸"而非"成品",JS 没跑,内容由 JS 生成
死链图片图片裂开、样式丢失CSS 和图片仍指向远程服务器,服务器一改或一关就失效
幽灵请求离线时仍在偷偷联网保存的 HTML 里还带着统计、推送、埋点脚本

一句话总结:"另存为"存的是别人的程序,而不是你看到的内容。页面从未真正属于你,它只是别人 JavaScript 的一个瘦客户端。

kage 的三阶段流水线

kage 走了另一条路:先用真实的浏览器把页面"看完",再撕掉所有脚本,最后把资源搬到本地。整条管线可以概括为一条流水线:

种子 URL → 无头 Chrome 渲染 → 最终 DOM 快照 → 剥离 JS → 本地化资源 → 落盘

下面逐阶段拆解。

阶段一:先渲染——让无头 Chrome 替你"看"完页面

kage 不是抓取 HTML 源码,而是驱动一个真实的无头 Chrome 打开页面,就像你亲眼去看它一样。核心逻辑在 browser/pool.go:

  • 等页面"安静"下来:加载完成后还会等待约 1.5 秒的网络空闲期(Settle),让 AJAX 数据、字体、图片全部到位,再对最终 DOM 拍快照——保存的就是人眼实际看到的那个页面;
  • 自动滚动:加--scroll参数后,kage 会模拟滚动整页,触发懒加载图片与无限流内容,再滚回顶部快照;
  • 有并发、有兜底:默认 4 个页面并行渲染(Workers),每页有 30 秒渲染超时,单页出错不会拖垮整场克隆;
  • 安全优先:Chrome 沙箱默认开启,禁止浏览器私自下载文件到磁盘,所有下载都走 kage 自己的下载器。

这一步解决的是"另存为"的死穴:内容必须先在浏览器里"活"过一次,才能被完整保存。

阶段二:再剥离——把"活页面"变成"死标本"

拿到渲染好的最终 DOM 后,kage 交给 sanitize/sanitize.go 做外科手术式清理。它用标准 HTML 解析器遍历整棵 DOM 树,删掉一切会动、会联网的东西:

  • 📄 所有<script>标签;
  • ✋ 所有onclick、onload等事件处理器属性;
  • 🔗 一切javascript:伪协议链接(替换为#);
  • ⏳<meta http-equiv="refresh">自动跳转;
  • 🚪preconnect、dns-prefetch等离线毫无意义的预连接提示;
  • 甚至包括藏在 IE 条件注释里、能绕过普通遍历的<script>。

同时它保留样式、图片、字体、表单和全部语义标签——布局原封不动。官方对此有一句绝妙的比喻:保存后的页面是一张照片,而不是一个程序。没有跟踪、没有网络调用、没有意外,就是一堆能直接双击打开的.html文件。

阶段三:后本地化——让每个链接都指向你的硬盘

前两阶段解决"内容完整"和"绝对安全",第三阶段解决"离线可用"。这一步由两个模块协作完成:

1. 确定性 URL→路径映射(urlx/urlx.go)

每个 URL 都会经过Normalize归一化(小写化 scheme/host、去 fragment、去默认端口),然后映射到一个确定的本地路径。妙处在于这是一个纯函数:不碰网络、不碰磁盘,所以页面工人可以在资源还没下载完之前,就先把它在 HTML 里的链接改写成本地相对路径——两边提前约定好"字节将来放在哪",天然支持并行。

2. 资源下载与改写(asset/)

页面里的<img src>、<a href>被asset.RewriteHTML批量改写;CSS 里的url(...)和@import则由 asset/css.go 中的RewriteCSS处理,指向的字体和图片同样拉回本地。资源走的是独立的普通 HTTP 下载池,与浏览器渲染互不阻塞。

整个过程的编排代码在 clone/cloner.go:先渲染 → 改写链接 → 剥离脚本 → 写入磁盘,一气呵成。

三阶段跑完,磁盘上长什么样?

镜像目录一目了然:

paulgraham.com/ ├── index.html # 首页,脚本已剥离 ├── greatwork.html # 某篇文章 └── _kage/ # 保留区:资源与爬取状态 ├── paulgraham.com/site.css # 本地化样式(url() 已改写) ├── paulgraham.com/pg.png └── state.json # 已访问集合,支持断点续爬

所有资源都躺在_kage/里,所有链接都已是相对路径。接下来怎么用,完全由你决定:

  • kage serve 目录—— 起个本地静态服务器,在浏览器里预览;
  • kage pack 镜像目录—— 压缩成单个.zim归档,或打包成一个自带网站的可执行文件,发给别人什么都不用装;
  • 用 webview 标签构建后,打开就是一个原生窗口里的离线站点,像真正的桌面应用。

与"另存为"的对比:思维方式变了

浏览器"另存为"kage
保存对象未渲染的 HTML 源码 + 部分附件渲染后的最终 DOM 快照
JavaScript原样保留,离线仍可能联网全部剥离,页面是"照片"不是"程序"
资源链接指向远程服务器全部改写为本地相对路径
SPA / 懒加载页面空白或残缺完整呈现,可自动滚动触发加载
断点续传无Ctrl-C 保存进度,下次接着跑

结语

回到开头的问题:浏览器"另存为"失败,是因为它试图保存一个永远在别人的服务器上运行的页面。而 kage 的三阶段原理给出了另一种答案——

📸先渲染,让你看到的成为你拥有的;✂️再剥离,让拥有变为安全;📦后本地化,让安全变为可随身携带。

这三步走完后,落盘的就不是一份网页副本,而是一份可以离线阅读十年、丢给任何设备都能打开的"网站快照"。想深入了解配置细节,可以查阅项目自带的文档 docs/ 与快速上手指南 docs/content/getting-started/quick-start.md。

【免费下载链接】kageShadow any website for offline viewing, with the JavaScript stripped out项目地址: https://gitcode.com/gh_mirrors/kage6/kage

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/27 3:02:49

FOC电流环程序实现:从原理到代码的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 2:56:11

文件类型识别指南:从文件头到扩展名,读懂12种常见格式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 2:55:58

SAR相位梯度自聚焦(PGA)MATLAB实战:运动误差补偿与成像质量提升

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 2:54:21

逆周期设备保卫战:山东制造业一把手的“4+1”法则,为何选淄博添键修大功率进口变频器及直流调速器?

—前4条是战略标配&#xff0c;第5条是穿越周期的底牌在制造业微利内卷的当下&#xff0c;真正能带企业穿越周期的顶级一把手&#xff0c;拼的不是产能规模&#xff0c;而是战略定力。那些把企业做到头部的掌门人&#xff0c;每天只死磕这5条法则。前四条&#xff1a;顶级一把手…

作者头像 李华