零脚本、零跟踪、零网络请求kage sanitize层如何把页面的JavaScript彻底切除【免费下载链接】kageShadow any website for offline viewing, with the JavaScript stripped out项目地址: https://gitcode.com/gh_mirrors/kage6/kagekage是一个开源的离线网页镜像工具它用真实无头浏览器渲染页面然后把JavaScript 彻底移除kage sanitize 层连同 CSS、图片、字体一起落到本地得到一份零脚本、零跟踪、零网络请求的离线副本。本文带你走读它的 sanitize/ 包看看这个切除到底是怎么做到的。为什么另存为不等于拥有这个网页现代网页早已不是一张纸而是一个薄客户端你看到的文字和图片大半是浏览器现场执行 JavaScript 之后拼出来的。用浏览器另存网页保存下来的往往是一个依赖脚本和网络的残骸——打开后是一屏空白或一个永远转圈的加载动画页面上的统计脚本仍会尝试回连已经不存在的服务端任何埋点、Cookie 追踪代码都原封不动地跟着文件走了。换句话说你保存的不是页面而是一把需要对方服务器配合才能打开的锁。kage 选择了另一条路让页面先把 JS 跑完、把最终形态定格下来然后再把 JavaScript 整体切除。留下来的就是一张照片a photograph, not a program——它长得和原站一样但不运行任何代码。负责这一步的就是 sanitize 层。kage sanitize 层在克隆流水线中的位置kage 的完整流水线只有五步sanitize 处于关键的第四环种子URL ─▶ 无头Chrome渲染 ─▶ 快照最终DOM ─▶ 切除JS(sanitize) ─▶ 资源本地化 ─▶ 写入磁盘实现上非常克制sanitize不是用正则搜罗HTML 字符串而是用golang.org/x/net/html把文档解析成一棵 DOM 树然后逐节点遍历、精准删除最后再渲染回 HTML。这个差别很重要——正则方案永远防不住嵌套和变形而树遍历不会。入口就两个函数位于 sanitize/sanitize.goStrip接收原始 HTML 字节解析→清理→渲染一步到位CleanTree接收一棵已解析的 DOM 树原地清理。克隆器用它这样 HTML 只解析一次资产链接重写asset/ 包和 JS 切除可以共享同一棵树省掉一次昂贵的解析。调用点在克隆器的页面写入路径上见 clone/cloner.goasset.RewriteHTML(root, j.u, sink) // 先把链接改成本地路径 sanitize.CleanTree(root, sanitize.Options{ KeepNoscript: c.cfg.KeepNoscript, MobileReadable: c.cfg.MobileReadable, Banner: cloned by kage from j.u.String(), })注意顺序先本地化链接再切除脚本。这样即使某个资源是脚本加载的影子页面里已经留下的 DOM 结构也安然无恙。六类切除sanitize 到底删了什么核心遍历逻辑在clean函数中sanitize/sanitize.go它自顶向下走遍整棵树对每个节点做判定。以下是它处理的六类目标1.script标签连根拔起所有script元素被整节点删除不管它是内联代码还是src引用外部 JS。这是零脚本的主力。2.on*事件处理器逐属性剥离div onclick...、body onload...这类内联事件处理器是最容易漏掉的 JS 藏身地。stripHandlerssanitize/sanitize.go扫描每个元素的全部属性凡是on开头的一律删除——onclick、onerror、onmousewheel一个不留。3.javascript:URL改写为无害形式a hrefjavascript:doEvil()是第三种执行路径。neutralizeJSURLssanitize/sanitize.go检查 8 种可能携带 JS 的属性href、src、action、poster、background等命中javascript:前缀的是href→ 改写为#链接还在但不再执行其他属性 → 整个属性直接丢弃。4. IE 条件注释堵住暗渡陈仓的通道这是 sanitize 层最见功力的一处。老式 IE 条件注释!--[if lt IE 9]...![endif]--在标准解析器眼里只是一条评论而评论里可以藏一个完整的script src...——纯按元素遍历的清理器永远看不见这个脚本。sanitize 的策略干脆利落识别到条件注释标记整条评论直接删掉sanitize/sanitize.go。而条件注释公开显示的那部分内容存放在兄弟节点里不受影响照留不误。5.meta refresh跳转JS 版本必删meta http-equivrefresh是无需脚本的跳转/刷新机制。目标里含javascript:的无论如何都删普通定时跳转默认也删除非你显式开启KeepMetaRefresh选项——离线副本不该自己动起来。6. 离线死链preconnect/preload等提示符link relpreconnect、dns-prefetch、modulepreload以及预加载.js文件的preload/prefetch——这些资源提示在线上是性能优化离线后全是指向空气的请求。isDeadLinksanitize/sanitize.go把它们识别出来并移除从根源上保证零网络请求。切除之外sanitize 还在默默修补sanitize 不只是减法还有几处贴心的加法让离线副本在任何阅读器里都自洽操作作用补charset声明若源站只在 HTTP 头里声明了编码保存为独立文件后会丢失、导致乱码。sanitize 会在head顶部补一个meta charsetutf-8让页面自我描述noscript解包可选默认删除noscript开启KeepNoscript后会把其中的真实内容解包保留——专为那些把正文藏在 JS 检测后面的老站移动端可读注入可选MobileReadable会为 90/00 年代表格布局老站注入viewport和一段 CSS放大字体、让固定像素表格变流式、隐藏离线无用的图片地图导航克隆横幅在文档头部插入一条 HTML 注释标注由 kage 从某 URL 克隆方便日后溯源保留清单同样明确样式表、图片、字体、表单、以及全部语义化标记原封不动——布局完整存活只是不再运行。一次切除的账单Report 统计结构每次清理都会生成一份Reportsanitize/sanitize.go逐项计数ScriptsRemoved删了多少scriptHandlersRemoved剥了多少on*属性JSURLsNeutralized改写/丢弃了多少javascript:URLMetaRefreshRemoved、DeadLinksRemoved、CondCommentsRemoved跳转、死链、条件注释各删了多少NoscriptRemoved/NoscriptUnwrappednoscript的去向CharsetAdded是否补了编码声明。这份账单既会出现在克隆运行的汇总统计里也是测试断言的依据——每一项切除都有据可查而不是感觉删干净了。测试如何保证切得干净sanitize/sanitize_test.go 覆盖了全部关键路径用例名本身就是一份清单TestStripRemovesAllJS—— 脚本、处理器、javascript:URL 一网打尽TestConditionalCommentScriptRemoved—— 条件注释里的暗藏脚本被清除TestConditionalCommentRevealedContentKept—— 而公开显示的内容完整保留TestKeepNoscriptUnwraps—— 解包模式工作正常TestDoctypePreservedAndBannerFollowsIt—— 横幅永远插在!DOCTYPE之后避免把老阅读器逼进怪异模式TestCharsetAddedWhenMissing/TestCharsetNotDuplicated—— 编码声明补而不重。想动手验证克隆一个站点后打开任意.html文件搜索script结果应当为空——而页面的图片、排版、链接却都在原位。结语一张照片而不是一个程序回到开头的问题为什么另存为保存不住网页因为网页的生命在 JavaScript 里而脚本既不能离线存活也带着跟踪与回连的副作用。kage 的 sanitize 层给出的答案是先让真实浏览器把页面活完定格下人类实际看到的那个 DOM再用树遍历把这个 DOM 里的所有执行能力——脚本标签、内联处理器、javascript:链接、条件注释后门、meta 跳转、死掉的资源提示——逐类切除。最终落盘的.html文件✅零脚本script与on*属性一个不剩✅零跟踪埋点代码根本不存在于文件里✅零网络请求预连接与预加载提示已清除CSS/图片/字体全部本地化✅自洽可读编码声明补齐任何离线阅读器kage 自带 viewer、Kiwix 等打开即所得。正如 sanitize/sanitize.go 包注释里那句话——a photograph, not a program一张照片而不是一个程序这就是离线镜像的完整体。更多使用方式可参考 clone/ 目录下的爬虫实现与 docs/content/ 中的完整指南。【免费下载链接】kageShadow any website for offline viewing, with the JavaScript stripped out项目地址: https://gitcode.com/gh_mirrors/kage6/kage创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
机器学习入侵检测实战:数据与特征比模型更关键 简介:这是一套基于Python机器学习的入侵检测系统项目代码,面向网络安全与机器学习方向的初学者及进阶学习者,可作为毕业设计、课程设计、大作业或工程实训的参考实现。压缩包共包含21个文件,以Python脚本、XML配置、Markdown说明等… · 2026/9/26 18:02:56
Go实现图像图层混合全指南:九种模式、Alpha合成与并发优化 最近写一个批量处理图片的小工具,要把两张图层按 Photoshop 常见的混合模式合成到一起。一开始想偷懒找现成库,结果不是绑了 CGO,就是只支持最简单的普通叠加,好不容易有个接口全的,依赖链又重得吓人。后来干脆自己用 … · 2026/9/26 18:02:56
从刷榜到落地:大模型真实场景应用开发实战与避坑指南 1. 从“刷榜”到“落地”:为什么真实场景成了大模型的新战场过去两年,我身边做AI的朋友聊天的画风经历了三次明显转变。2023年上半年,大家见面第一句是“你那边卡够不够”;2023年下半年变成“你们微调用的什么数据集”;… · 2026/9/26 18:37:07
从零手写小型编译程序:词法分析、语法分析与代码生成实战 简介:这份资源面向学习编译原理、需要完成课程设计的高校学生,围绕SLR(1)分析法实现一个小型编译程序,解决从高级语言源程序到四元式程序翻译的实践问题。资源包共14个文件,约22KB,以c源码、dat测试数据、asm汇编输出、… · 2026/9/26 18:37:07
手写小型编译程序:从词法分析到栈式虚拟机的完整实现指南 简介:这份资源面向学习编译原理、需要完成课程设计的高校学生,围绕SLR(1)分析法实现一个小型编译程序,解决从高级语言源程序到四元式程序翻译的实践问题。资源包共14个文件,压缩后约22KB,以c源码、dat测试数据、asm汇编… · 2026/9/26 18:37:07
Flask搭配Django开发化妆预约系统:微信小程序全栈实践 做化妆造预约系统,前后端技术栈怎么配才顺手?这个标题里同时出现了 Flask 和 Django,老实说第一次看到的时候我也愣了一下——这两个框架平时很少出现在同一个项目里。但实际做下来你会发现,这个组合不但不冲突,反而把… · 2026/9/26 18:37:07
Java GC核心知识点全梳理:GC Root、循环引用与三色标记法详解 Java GC核心知识点整合:从GC Root到三色标记法的一次彻底梳理每次排查线上OOM或者JVM频繁Full GC的时候,我总会习惯性地先打开堆转储文件,顺着引用链一路往上翻。翻到最顶端的某个"根"时,真相往往就藏在那条引用链上。这… · 2026/9/26 18:37:07
Jev决策模型与TypeSafe AI:从API Key到置信度路由的完整工程实践 1. Jev 在 TypeSafe 决策体系里到底扮演什么角色1.1 Jev 与 TypeSafe AI 的关系先说个容易混淆的点:Jev 不是某个 JavaScript 工具库,也不是冷门框架的名字,它是 TypeSafe 决策体系里的一个模型服务。和常见的聊天模型不同,Jev 的… · 2026/9/26 18:37:00
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46