HTML → Markdown 转换器,免费

将 HTML 代码转换为干净的 Markdown。

支持的 HTML 元素

标题:<h1> 到 <h6> → # 到 ######

强调:<strong>、<em>、<del> → **粗体**、*斜体*、~~删除线~~

链接:<a href> → [文本](url)

图片:<img> → ![alt](src)

代码:<code>、<pre> → 行内代码和围栏代码块

列表:<ul>、<ol> → - 项、1. 项

表格:<table> → Markdown 表格语法

其他:<blockquote>、<hr>、<br>

HTML 转 Markdown 转换器到底在做什么

一个 HTML 转 Markdown 转换器会解析一段 HTML 片段,遍历得到的 DOM 树,并为它能识别的每一个元素发出 Markdown 语法。<h1> 变成 #<strong> 变成 **粗体**<a href="..."> 变成 [文本](url)<ul><li> 变成一个项目符号列表。这个工具完全在你的浏览器中通过 JavaScript 运行:在左边粘贴 HTML,点击 转换为 Markdown,格式化后的输出就会出现在右边。没有上传、没有服务端往返、没有遥测,你可以在点击“转换”时打开开发者工具的网络标签页查看,或者在页面加载完成之后让它离线(飞行模式),转换器仍然能用。本实现使用浏览器内置的 DOMParser 来读取 HTML,再用一个小的递归遍历器为每个节点发出 Markdown。这是一个手写的、约 150 行的转换器,而不是 Turndown 的封装,意味着它把常见情形处理得干净,但并不具备 Turndown 那种完整的可配置性。

什么时候你真的需要这种转换

反方向(Markdown 转 HTML)是更出名的那一边,每一个静态站点生成器和写作工具都会做。正方向(HTML 转 Markdown)不那么显眼,但越来越常见,因为写作工具生态已经分化:HTML 是 Web 的环境格式(每一个 CMS、邮件通讯平台、CRM 模板、老的静态站点都在产出或存储 HTML);而 Markdown 是 2014 年前后出现的所有现代文档、笔记和受版本控制内容工作流的原生格式。有四类真实工作流会产生这种转换需求。

参考实现:Turndown 及其家族

Turndown(Dom Christie)是占主导地位的 JavaScript HTML 转 Markdown 库,它在 2012 年作为 to-markdown 起步,2017 年为了与各种分支区分而改名为 Turndown,以 MIT 许可证在 npm 上以 turndown 发布。它的设计是基于规则的:每条规则有一个 filter(决定该规则在哪些 DOM 节点上触发)和一个 replacement(一个产出 Markdown 的函数)。其构造函数接受用于标题样式(atx # 还是 setext ===)、项目符号标记(-+*)、代码块样式(缩进还是围栏)、强调定界符(* 还是 _)、加粗定界符(** 还是 __)、链接样式(内联还是引用)等的选项。表格、删除线、任务列表项和自动链接住在另一个独立包 turndown-plugin-gfm 中。markdownify(Matthew Tretter)是 Python 中的对应物,在抓取流水线、Jupyter notebook 转换、LangChain 文档加载器和 LLM 数据集准备中被广泛使用。html2text(最初由 Aaron Swartz 编写,他在 2004 年也与 John Gruber 合作了 Markdown 的最初设计)是更早的 Python 选项,仍然在一些遗留邮件流水线里使用,但大体上已被取代。html-to-markdown(Johannes Kaufmann)是 Turndown 的一个 Go 移植版,受到自包含抓取二进制程序的青睐。Pandoc(John MacFarlane,CommonMark 项目主席)是通用文档转换器,通过 grid table 处理含合并单元格的表格,以及数学、引文、脚注、定义列表,并能在数十种格式之间互转。Pandoc 是现有最强大的 HTML 转 Markdown 工具,但它是一份 60 MB 以上、需要安装的 Haskell 二进制程序;它不在浏览器里运行。

根本性的取舍:HTML 比 Markdown 更丰富

每一次 HTML 转 Markdown 的转换都必然是有损的,因为源格式表达的东西,目标格式表达不了。内联样式(<span style="color:red">)没有 Markdown 语法,Markdown 的强调词汇严格只有粗体/斜体/删除线/代码,并没有用来表达任意颜色、字体或字号的语法。CSS 类(<div class="alert">)对样式表有意义,对 Markdown 则没有。自定义 data 属性(data-track-event="...")属于该页面的 JavaScript 契约,而不是文档。带合并单元格(colspanrowspan)的表格在 GFM 管道表中没法表达。嵌入式媒体(<video><audio><iframe>)和表单控件在 Markdown 中没有对应物。<details><summary> 可折叠块、<figure><figcaption>、用于 CJK 注音的 <ruby>、microdata 与微格式,这些都不会在转换中存活下来。对每一种不被支持的结构,转换器作者都需要在三种策略里做选择:翻译到一种会丢失部分信息的 Markdown 近似;原样穿过,把它作为内嵌在 Markdown 里的原始 HTML(Markdown 规范是允许这样的;CommonMark 第 4.6 与 6.6 节都覆盖了这一点);或者干脆丢弃。本实现选择的是“在有清晰映射的地方翻译,否则透明包裹(渲染子节点,扔掉标签)”,一个可预测、容易讲清楚的默认行为,以放弃高级可配置性为代价处理好常见情形。

经典对应关系

诚实的范围:本工具做什么、不做什么

三条值得了解的诚实限制。(1) 内联样式与 CSS 类会被丢弃。一个 <span style="color:red"> 会变成无样式文本;一个 <p class="lede"> 会丢掉它的类。Markdown 没有用于任意内联样式的语法。(2) 含合并单元格的表格会被压平。GFM 管道表没有 colspanrowspan 的语法;合并单元格信息会被悄无声息地丢掉。对复杂表格,要么把源保留为 Markdown 内嵌的 HTML(CommonMark 允许嵌入 HTML),要么使用 Pandoc 输出 grid table。(3) 代码块发出时不带语言提示。如果你的 HTML 里有 <pre><code class="language-js">,目前会丢掉这个语言属性,输出是一个不带语言的围栏代码块。如果你的目标渲染器支持语法高亮,可以在起始反引号之后手工补上语言标识符。更大的提醒:如果你把一个网页的完整 HTML(来自“查看页面源代码”)粘进来,<script><style> 的内容会被当作纯文本输出,这几乎肯定不是你想要的。修复方式是只粘贴文章正文,或者从渲染视图里复制(这会自动剥掉脚本和样式),或者在转换前先用 DOMPurify 等工具对 HTML 做净化。

2026 年的 Markdown 是什么样子

Markdown 在 2026 年迎来了 22 岁。John Gruber 于 2004 年发布了最初的 Perl 脚本,Aaron Swartz 是设计上的合作者。Gruber 的原始版有意没有表格;今天大多数读者熟悉的管道表语法源自后来的方言,最具代表性的是 GitHub Flavored Markdown。CommonMark,由 Jeff Atwood 与 John MacFarlane 在 2014 年组织的严格规范化努力,如今已发展到 0.31.2 版(2024 年 1 月 28 日),是大多数现代解析器的目标方言。GitHub Flavored Markdown(GFM,于 2019 年 4 月 6 日在 0.29-gfm 版正式定形)是 GFM 在 CommonMark 之上扩出来的超集,加入了表格、任务列表、删除线、自动链接以及禁止原始 HTML 的规则。由于 GitHub 的体量,GFM 是大多数用户实际在网页上看到的方言。Markdown 如今已是几乎每一个开发者文档生态的原生格式;HTML 仍然是 Web 的通用输出格式;二者之间的转换与反向转换一样常见,也正因如此,它会出现在你需要它的那一刻,在浏览器里、不必安装、也不会有数据离开你的设备。

隐私:为什么“仅在浏览器”在这里很重要

粘进转换器的 HTML 经常带有原始来源的痕迹(内部 CMS 标记、还没发布的草稿内容、邮件模板里的客户数据、暴露了内部站点结构的链接 URL、指向私有资源服务器的图片引用。服务器端转换器会把这些全部上传到第三方服务。本工具完全在你的浏览器中通过 JavaScript 运行:你粘贴的 HTML 永远不会跨越网络)你可以在点击“转换”时打开开发者工具的网络标签页查看,或者在页面加载完成之后让它离线(飞行模式),转换器仍然能用。对未发布的草稿、面向客户的邮件模板、内部文档摘要,或任何你不希望被复制到陌生人硬盘上的 HTML 都安全。

常见问题

对很大的文件也能用吗?

可以,因为转换在你的浏览器里运行,实际上限是你设备的可用内存。在一台现代笔记本上,几万行的输入也能在远不到一秒内完成转换。非常大的输入(数百万节点)在 DOM 遍历器递归时可能让标签页短暂卡顿。要批量转换整份 CMS 导出,更合适的做法是写一个脚本,在 Node 里用 Turndown,或在 Python 里用 markdownify。

内联样式和 CSS 类会怎么样?

完全被丢弃。Markdown 的强调语法只覆盖粗体、斜体、删除线和代码;并没有用于任意颜色、字体、字号或基于类的样式的语法。如果视觉样式对你的输出很重要,要么把原件保留为 HTML,要么换一个更丰富的目标格式,例如 AsciiDoc、reStructuredText 或 MDX(Markdown 加 JSX 组件,被 Docusaurus 使用)。对本工具构建所瞄准的“归档文章”和“CMS 迁移”这两种用例而言,丢掉样式是正确的行为,Markdown 的整个意义就在于剥掉视觉噪声、只保留结构。

本工具能离线工作吗?

能,一旦页面加载完成,转换就完全在你浏览器里的 JavaScript 中运行。转换过程中没有网络调用。你可以在点击“转换”时打开开发者工具的网络标签页查看,或者在页面加载完成之后让设备离线(飞行模式),工具仍然可用。

这是 Turndown 吗?

不是。Turndown(Dom Christie 的库)是 JavaScript 中的参考实现,也是 Node 项目里自然会去用的工具,但它是一项体量不小的依赖,对标题样式、项目符号标记、链接样式、代码块样式等都有完整的可配置能力。本浏览器内工具是一个更小、手写的 DOM 遍历器(大约 150 行)目标只是处理常见情形(标题、段落、强调、链接、图片、列表、块引用、围栏代码、基础表格),并不带可配置面。对本站构建所瞄准的工作流(在浏览器里做一次性转换、零安装)而言,更小的实现是合适的形态;对需要可配置规则的生产抓取流水线,Turndown 仍然是正确的选择。

表格是怎样处理的?

按 GFM 管道表处理:一行表头、一行用短横线组成的分隔行,外加每一个 <tr> 对应一行主体。管道表是扁平的,它没法表达 colspanrowspan、跨多行的单元格内容、单元格里的列表,也没法表达逐列的对齐方式。如果你的 HTML 表格用了上面任何一项,本转换器会输出一个降级的管道表,丢失掉这些额外结构。对复杂表格,有两个实用选项:(a) 把表格保留为 Markdown 里的原始 HTML(CommonMark 允许嵌入 HTML)并相信目标渲染器会让它原样通过;(b) 使用 Pandoc 并选择 grid table 输出,这样可以表达合并单元格。

我能把整个网页的 HTML 都粘进来吗?

可以,但你大概不应该这么做。一个现代网页的完整源码里包含带 JavaScript 代码的 <script> 标签、带 CSS 的 <style> 块、追踪像素、广告标记,以及 CMS 模板的注释。本转换器并不会显式剥掉脚本和样式的内容,所以这些东西都会作为纯文本进入你的 Markdown 输出。干净的做法:在开发者工具里只选中文章元素(在文章上点击右键,选“检查”,再在 Elements 面板里对应的节点上点击右键,选“Copy outerHTML”),或者在粘贴前先做一步内容提取(用 Mozilla 的 Readability 库,或它在 Firefox 阅读模式中的封装版本)。如果你想要那种自动完成提取步骤的浏览器扩展工作流,可以看看 Obsidian Web Clipper 或 MarkDownload。

相关工具