Defuddle 返回导航链接清理实战:从 fixture 案例到 content-patterns 源码解析
后端【免费下载链接】defuddleGet the main content of any page as Markdown.项目地址https://gitcode.com/gh_mirrors/de/defuddle点击查看免费下载本文以仓库中的 general--back-nav-link.md 测试夹具为入口剖析 Defuddle 如何在提取网页正文时自动识别并移除页面顶部的返回上一级导航链接如← back、↑ index。读完本文你将理解该清理规则的判定条件、底层实现content-patterns.ts以及 fixtures 测试机制如何保证这类输出稳定可回归。从一个 fixture 案例看提取结果general--back-nav-link.md 是 Defuddle 对 general--back-nav-link.html 处理后的期望输出。其输入页面结构非常典型在h1之前有一个指向父目录的返回链接然后是文章正文!-- {url: https://example.com/articles/sorting} -- a href../index.html← back/a h1An Article About Sorting/h1 p classmetaJanuary 1, 2025/p pSorting algorithms are fundamental to computer science. .../p对应的期望输出即关联文档由两部分组成JSON 元数据前言以 json 代码块形式输出title、author、site、published四个字段便于人工对比与审查Markdown 正文只保留标题与段落正文页面顶部的a href../index.html← back/a已被完全清除也没有留下空行残骸。这个案例直观展示了 Defuddle 的两项核心能力结构化元数据提取与正文去噪。其中返回导航链接被移除正是由下文介绍的removeByContentPattern中专门的分支逻辑完成的。返回导航链接的识别规则清理逻辑位于 content-patterns.ts 的Remove section breadcrumbs and back-navigation links段落。其目标元素是短文本的div, span, p及独立的裸a元素匹配前提是链接指向当前 URL 的父路径共有两种模式直接路径前缀链接路径是当前 URL 的路径前缀例如当前为/blog/2024/post链接为/blog/或/blog父目录索引页链接指向父目录下的index.html/index.php例如当前为/articles/hensels链接为../index.html解析后等价于/index.html。在 fixture 案例中页面 URL 为https://example.com/articles/sorting链接../index.html解析后路径为/index.html满足isParentIndex判定/^index\.(html?|php)$/i且urlPath.startsWith(linkDir)因此被移除。代码通过以下条件约束避免误伤正文内的正常链接字数上限元素文本countWords后不得超过 10 个词words 10直接跳过叶子元素元素内部不得再包含p, div, section, article等块级子元素裸a特判若父元素文本与链接文本完全一致说明该链接是独立元素否则视为流动正文中的内联链接而跳过除非满足两个例外——链接不在p内或位于首个标题h1/h2/h3之前。最后一个例外正是为 fixture 这种页眉返回链接场景设计的注释明确写道出现在首个标题之前的嵌入a元素属于页面头部的返回导航链接而非正文内联链接content-patterns.ts。文档顺序判断isNodeBefore位于首个标题之前的判定依赖 src/utils/dom.ts 中的isNodeBefore工具函数。它不依赖 linkedom 跨父节点的compareDocumentPosition该实现可能不一致而是通过祖先链比对 兄弟节点遍历自行推导文档顺序分别收集两个节点到根的祖先路径若根不一致处于分离子树则返回false从根向下弹出公共祖先直到分叉点从分叉点的第一个节点开始沿nextSibling向后查找若能遇到第二个节点则说明前者在前。这样无论底层 DOM 实现是 linkedom 还是 jsdom参见 helpers.ts 的parseDocument切换removeByContentPattern都能获得稳定的顺序判断结果。与相邻清理模式的配合返回链接清理并不是孤立逻辑它处在removeByContentPattern的前置内容清理链条中同一函数还包含面包屑列表移除内容顶部首个ul/ol若被isBreadcrumbList判定为导航列表连同单子包装容器一并删除content-patterns.ts促销横幅链接首个h1之前、含块级子元素div、文本较短的a会被当作公告横幅移除L379-L394hero 头部块包裹日期、作者、标签与 hero 图的容器在元数据剥离后被整体清理。这些规则共享一个内容起点锚点findContentStartcontent-boundary.ts它先定位与页面标题匹配的h1/h2再沿文档序找到第一个散文长度的块级元素作为正文从哪里开始的权威参考替代了早期按字节偏移如contentText.indexOf(text) 300的脆弱做法。fixture 测试如何保证输出稳定general--back-nav-link.html 属于tests/fixtures/下的自动化夹具体系由 fixtures.test.ts 驱动扫描tests/fixtures/下所有.html文件从文件头部!-- {url: ...} --注释读取测试 URL调用Defuddle(doc, url, { separateMarkdown: true, fetch: offlineFetch })提取内容——offlineFetch强制禁用网络保证结果确定性将title/author/site/published序列化为 JSON 前言与 Markdown 正文合并成期望文件createComparableResult与tests/expected/中已保存的期望结果比对不一致即测试失败。若期望文件不存在测试会自动创建基线saveExpectedResult更新期望值的方法是删除对应期望文件后重新运行npm test。因此当有人误改了返回链接清理规则导致输出变化时fixture 对比会立刻报警防止回归。在项目外复现该行为你可以在任何 Node.js 项目中按如下方式复现仓库源码位于 src/node.ts 的Defuddle入口import { Defuddle } from defuddle; import { parseLinkedomHTML } from defuddle/utils/linkedom-compat; // 或使用 jsdom const html !DOCTYPE htmlhtmlheadtitleAn Article About Sorting/title/head bodya href../index.html← back/a h1An Article About Sorting/h1 pSorting algorithms are fundamental.../p/body/html; const doc parseLinkedomHTML(html, https://example.com/articles/sorting); const result await Defuddle(doc, https://example.com/articles/sorting, { separateMarkdown: true }); console.log(result.contentMarkdown); // 不含 ← back console.log(result.published); // 由 p classmeta 等日期文本推断注意两点限制一是URL 必须真实传入——urlPath为空时整段返回链接清理不会执行这正是 fixture 头部注释携带url的原因二是输出中的published字段来自 metadata.ts 的getPublished优先取 Schema.org 的datePublished、publishDate、article:published_time等 meta 标签再扫描h1前后三个兄弟元素中的p/time日期文本本案例的2025-01-01即来自 byline 文本January 1, 2025。小结从 general--back-nav-link.md 这一个期望文件出发可以看到 Defuddle 处理返回导航链接的完整链路removeByContentPattern依据 URL 路径前缀/父目录索引页两种模式识别链接用字数、叶子结构、标题位置与isNodeBefore文档序判定约束边界最后通过 fixtures 自动化测试将行为固化为可回归的期望输出。若你的站点在正文头部有返回列表类链接这一规则会默认生效而若某些内联链接被误删调整 content-patterns.ts 中的匹配条件后更新对应 fixture 期望即可安全迭代。赞分享后端【免费下载链接】defuddleGet the main content of any page as Markdown.项目地址https://gitcode.com/gh_mirrors/de/defuddle点击查看免费下载相关推荐defuddle 如何处理无效的 codepre 嵌套fixture 用例与两阶段源码实现解析defuddle 如何处理无效的 code pre 嵌套fixture 用例与两阶段源码实现解析 本篇技术指南以 codeblocks code pre后端BuildAdmin内置WEB终端深度探索无需手动npm install的智能开发体验BuildAdmin内置WEB终端深度探索无需手动npm install的智能开发体验 BuildAdmin是一款集颜值、实用、敏捷于一身的管理系统技术栈为后端前端低代码认证鉴权企业应用void 仓库 Markdown 相对链接解析实战链接格式、锚点导航与源码级实现void 仓库 Markdown 相对链接解析实战链接格式、锚点导航与源码级实现 导读 本文以 void 仓库内 markdown language feat代码编辑器开发工具AI Agent人工智能上一篇为什么选择esp32-snippets深度解析这个ESP32开发者的秘密武器下一篇CANN/asc-devkit矢量乘法API创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Lunar 2.8.1 修复解析:显示器 UUID 分配、名称检测与缓存数据库覆盖机制

Lunar 2.8.1 修复解析:显示器 UUID 分配、名称检测与缓存数据库覆盖机制

桌面应用 【免费下载链接】Lunar Intelligent adaptive brightness for your external monitors 项目地址: https://gitcode.com/gh_mirrors/lu/Lunar 点击查看 免费下载 本文围绕 Lunar(macOS 外部显示器智能亮度调节工具)2.8.1 版本的三个…

2026/10/15 2:12:16 阅读更多 →
MLeaksFinder 实践与源码解析:在开发阶段自动定位 iOS 内存泄漏

MLeaksFinder 实践与源码解析:在开发阶段自动定位 iOS 内存泄漏

开发工具质量保障 【免费下载链接】MLeaksFinder Find memory leaks in your iOS app at develop time. 项目地址: https://gitcode.com/gh_mirrors/ml/MLeaksFinder 点击查看 免费下载 MLeaksFinder 是腾讯开源的 iOS 内存泄漏检测工具,其核心思路是&a…

2026/10/15 2:11:16 阅读更多 →
协处理器系统集成实战:从硬件接入到驱动同步的完整指南

协处理器系统集成实战:从硬件接入到驱动同步的完整指南

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

2026/10/15 2:11:16 阅读更多 →

最新新闻

ESXi 升级到 8.0 后 VM 快照删不掉?一篇讲透 “in progress“ 死循环的 3 种解法

ESXi 升级到 8.0 后 VM 快照删不掉?一篇讲透 “in progress“ 死循环的 3 种解法

本文适用版本:ESXi 7.0 U3 → 8.0 U2 升级场景(vSphere 6.7 升级也会遇到) 阅读时长:约 8 分钟 难度:⭐⭐⭐(操作不可逆,生产 VM 强烈建议先备份再动)一、为什么写这篇文章?最近私信里又有几位网友问:ESXi 7.0 升到 8.0 之后,VM 的快照怎么都删不掉,vSphere Client 里一直显示…

2026/10/15 2:48:27 阅读更多 →
ESXi ping 得通但连不上 vCenter?一篇讲透 hostd 假死的全套救法

ESXi ping 得通但连不上 vCenter?一篇讲透 hostd 假死的全套救法

本文适用版本:ESXi 7.0 U3 / 8.0 U2 / 9.0 GA 阅读时长:约 7 分钟 难度:⭐⭐(SSH 能进就能修,但要分清是 hostd 还是 vpxd 的锅)一、为什么写这篇文章?最近私信里又陆续收到几位网友问:ESXi 能 ping 通、SSH 也能进、DCUI 也正常,但 vCenter 里主机显示"未响应"或&q…

2026/10/15 2:48:27 阅读更多 →
前端XSS防御实战:xss-filters上下文转义库详解

前端XSS防御实战:xss-filters上下文转义库详解

简介:前端开源库-xss-filters是一份面向前端开发者与安全入门者的XSS防护工具源码包,聚焦于解决用户输入回显场景下的跨站脚本注入风险。资源共30个文件,以20个js源码与测试脚本为主体,辅以3个json配置、3个md说明文档&#xff0c…

2026/10/15 2:48:27 阅读更多 →
ESXi 装系统报错 “bootbank is corrupted“ 怎么办?一篇讲透三种根治方案

ESXi 装系统报错 “bootbank is corrupted“ 怎么办?一篇讲透三种根治方案

本文适用版本:ESXi 7.0 U3 / 8.0 U2 / 9.0 GA(三版统一报错,解决方案略有差异) 阅读时长:约 8 分钟 难度:⭐⭐⭐(需在 DCUI/物理机前操作,不建议生产机远程盲操作)一、为什么写这篇文章? 最近陆续有几位网友私信问同一个问题:装 ESXi 的时候跑到一半,屏幕突然卡住,报 bootbank…

2026/10/15 2:48:27 阅读更多 →
React Native position 定位详解:relative 与 absolute 实战指南

React Native position 定位详解:relative 与 absolute 实战指南

1. 为什么 position 定位值得单独拎出来讲做 React Native 开发的人,迟早都会在布局上栽跟头。Flexbox 那一套东西,flexDirection、justifyContent、alignItems三板斧抡完,大部分界面确实能搭出来。但总有一些场景,光靠 Flex 流式…

2026/10/15 2:48:27 阅读更多 →
从零开发聚合9大视频网站的桌面App:技术选型与发布运营复盘

从零开发聚合9大视频网站的桌面App:技术选型与发布运营复盘

前阵子我在一个技术交流群里发了句感叹:“现在做桌面应用,是不是有点逆潮流?”结果有个朋友直接回我:“你做一个有用的桌面工具试试,用户在乎的是好不好用,又不是你用什么平台。”我当时不以为然&#xff0…

2026/10/15 2:47:27 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/14 7:53:34 阅读更多 →