ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

kage代码架构全景解剖:从frontier爬虫、Chrome渲染池到纯Go实现的ZIM读写器

kage代码架构全景解剖:从frontier爬虫、Chrome渲染池到纯Go实现的ZIM读写器 kage代码架构全景解剖从frontier爬虫、Chrome渲染池到纯Go实现的ZIM读写器【免费下载链接】kageShadow any website for offline viewing, with the JavaScript stripped out项目地址: https://gitcode.com/gh_mirrors/kage6/kagekage 是一个纯 Go 编写的网站快照website mirror工具它用无头 Chrome 渲染整站、剥掉全部 JavaScript把网站冻结成可离线浏览的本地镜像还能压缩进单个 ZIM 文件。本文带你从全局到细节解剖 kage 的代码架构——frontier 爬虫引擎、Chrome 渲染池、确定性 URL 映射以及手写实现的 ZIM 读写器看看一个看起来像现网站、但一行代码都不运行的镜像是如何诞生的。一张图看懂 kage 的分层架构kage 的仓库按职责切分每个目录都是一个独立的关注点依赖关系非常清晰cmd/kage/ 入口固定主线程后交给 cli.Execute cli/ cobra 命令树与参数解析 clone/ 爬虫核心frontier、渲染 worker、资源 worker、断点续爬 browser/ 无头 Chrome 控制与 DOM 快照 sanitize/ 剥离脚本、事件处理器、javascript: 链接 asset/ 下载并本地化 CSS、图片、字体 urlx/ 确定性的 URL ⇄ 文件路径映射 zim/ 纯 Go 的 ZIM 读取器与写入器 pack/ 镜像打包为 ZIM 或自包含二进制 viewer/ 展示方式系统浏览器或原生窗口数据流只有一条主线来自 README.md 的 How it works 一节seed URL ─▶ 无头 Chrome ─▶ 最终 DOM ─▶ 剥离 JS ─▶ 本地化资源 ─▶ 磁盘 (渲染) (快照) (消毒) (重写链接)记住这条流水线后面每个模块都在为它的某一段服务。frontier 爬虫去重、限流与断点续爬的精髓爬虫的主循环在 clone/cloner.go 中而它的记忆由 clone/frontier.go#L16-L22 中的frontier结构体承担。这个结构体非常小只有三张 map状态含义seen已见过入队或已访问的 URLvisited已完整写盘的页面pending已发现但还没做完的页面含深度信息三个设计值得新手借鉴 以输出文件为去重键。pageKey返回的不是 URL 字符串而是这个 URL 最终会写成的本地文件路径见 cloner.go#L97-L108。于是http与https、/与/index.html、带不带尾斜线这些长得不同但指向同一页的 URL天然只会爬一次。失败的页面刻意不标记完成。markDone只用于 robots.txt 明确拒绝的页面渲染失败的页面会留在 frontier 里下次--resume自动重试——这是记住失败的断点续爬能力。原子保存状态。save采用写临时文件再 rename的方式frontier.go#L139-L167Ctrl-C 退出时状态不会写坏。并发模型也很朴素优雅Run启动两批 workercloner.go#L153-L170一批消费pageJobs通道负责渲染页面另一批消费assetJobs通道负责下载资源页面渲染中遇到的每个资源链接只是入队不阻塞渲染。Chrome 渲染池让 JS 页面现出原形browser/pool.go 是整个项目的工程含金量所在。Pool拥有一个Chrome 进程用带缓冲的 channel 作信号量sem chan struct{}限制同时打开的页面数——这就是渲染池名字的由来。一次Render的完整流程包含好几个坑位处理注入 stealth 脚本internal/stealth/避免被网站识别为自动化工具监听主文档的 Content-Type如果导航目标其实是 zip、CSV、图片issue 里踩过的真实坑返回ErrNotHTML把 URL 转交给资源下载器而不是存下一个坏页面pool.go#L86-L130网络静默等待settle等网络空闲指定毫秒后才快照 DOM并设了硬超时上限话痨页面永远不会挂死 worker自动滚动--scroll时用一段内嵌 JS 找到真正会滚动的那个元素很多应用壳的body是固定高度滚动触发懒加载再滚回顶部pool.go#L603-L651;补回 doctypeChrome 序列化的outerHTML不含 doctype缺失会导致页面以 quirks 模式渲染、版式错位。kage 从页面里读回 doctype 三个字段在 Go 侧严格校验后重建pool.go#L188-L203——细节控才能写出这种十年后还能打开的镜像。安全方面Chrome 沙箱默认开启只在容器或 root 环境下关闭且打印日志告知pool.go#L410-L433浏览器级禁止下载爬虫绝不会往用户的 Downloads 文件夹里塞文件。sanitize把照片和程序分开sanitize/sanitize.go 的注释一句话点题删除 HTML 中每一处 JavaScript 的痕迹让保存的页面变成一张照片而不是一个程序。它用x/net/html解析 DOM 后遍历删除script标签、onclick之类的事件处理器、javascript:URL、能夹带脚本的 IE 条件注释、离线无意义的 preconnect 提示——同时保留样式、图片、字体、表单和全部语义结构让版式原样存活。每次运行还会生成一个Report统计删掉了多少脚本、多少处理器用于最终报告。urlx确定性映射整个项目的地基契约urlx/urlx.go 是个纯函数包无网络、无文件系统、无时钟却回答了爬虫最重要的问题任意 URL 会落在磁盘的哪里Normalize把 URL 规范化小写 scheme/host、去 fragment、去默认端口、清理路径urlx.go#L118-L149LocalPath把规范化 URL 映射为镜像根下的相对路径页面镜像 URL 路径资源统一收进_kage/保留目录InScope/SameRegistrableDomain决定链接要不要爬用 Public Suffix 列表把www.apple.com、images.apple.com归为同域而第三方 CDN 和追踪器则留在线上cloner.go#L519-L527 的wantAsset就靠它。正是这份双方提前约定字节住哪的确定性让页面 worker 可以在资源还没下载完时就先把 HTML 里的链接重写好——这也是断点续爬能成立的根本。纯 Go 的 ZIM 读写器80 字节头部与两遍写zim/ 包是项目最硬核的部分不依赖任何 C 库从零实现了 ZIM 离线归档格式Kiwix/Wikipedia 离线版所用的开放标准。文件格式zim/format.go文件开头是 80 字节固定头部内含魔数0x44D495A、UUID 和三组指针位置随后依次是 MIME 列表、URL/标题/簇指针表、目录条目区、内容簇区文件尾部一个 MD5。所有内容交叉引用都是记录在头部里的绝对偏移全部小端编码。写入器zim/writer.go采用先规划、后输出的两遍策略条目按namespaceurl排序、分配索引排序保证了后续可二分查找解析重定向目标、建立 MIME 索引打包内容簇文本zstd 压缩与二进制原样存储分开成簇每簇上限 2 MiB兼顾压缩率与解压成本writer.go#L11-L14统一分配各区绝对偏移最后才一次性把各段写出并算出覆盖全文件的 MD5。还有一个漂亮的细节归档 UUID由内容推导而非随机所以同一镜像打包两次产出字节级一致的文件——可以放心做校验和与缓存pack/zim.go#L23-L25 也把时间戳从 CLI 传入保持包纯度。读取器zim/reader.go则展示了如何不解压整个文件就能随机访问Get对 URL 排序的目录做二分查找命中后只解压对应簇并缓存reader.go#L172-L192重定向最多跟随 16 跳防死循环。这就是kage open xxx.zim能秒开离线网站的底层原因。从 ZIM 到原生窗口pack 与 viewer 的最后一公里pack/zim.go 的BuildZIM遍历镜像目录把每个文件变成C/内容条目、推断 MIME、选出主页面、写入元数据——注意它几乎不需要重写任何链接镜像里的链接本来就是镜像相对路径与 ZIM 条目一一对应。pack还能把归档粘到 kage 可执行文件尾部产出一个自带 HTTP 服务、双击即用的自包含二进制。再看终点。默认构建用系统浏览器打开站点而用webview标签构建viewer/webview.gopack/ 打包出来的程序会调用操作系统 WebViewmacOS 的 WKWebView、Windows 的 WebView2、Linux 的 WebKitGTK让离线镜像开在一个真正的原生窗口里——没有标签页、没有地址栏观感上就是一个独立 App如何按这条路径读 kage 源码给想深入源码的新手一份阅读顺序建议 cmd/kage/main.go → cli/clone.go从命令到参数的最短路径clone/cloner.go主循环与双 worker 池架构的心脏clone/frontier.go不到 200 行把去重与断点续爬想得很透browser/pool.go读注释每一段都在讲一个踩过的真实坑issue #16/#32/#36/#61urlx/urlx.go纯函数、测试最密集适合建立确定性直觉zim/format.go → zim/writer.go → zim/reader.go按格式规范顺序读二进制格式的最佳范本。kage 的架构哲学可以浓缩成一句话用确定性URL→路径→簇偏移换取一切——可续爬、可重打包、可字节级复现、可被任何标准 ZIM 阅读器打开。想亲手验证参考 docs/content/getting-started/ 的入门文档一条kage clone命令就能看到本文解剖的整条流水线跑起来。【免费下载链接】kageShadow any website for offline viewing, with the JavaScript stripped out项目地址: https://gitcode.com/gh_mirrors/kage6/kage创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表