xberg-io/html-to-markdown · 上手攻略
- 仓库:xberg-io/html-to-markdown
- 链接:https://github.com/xberg-io/html-to-markdown
- 分类:工具库 / HTML→Markdown 转换 / 多语言绑定
- 作者:spark
- 更新:2026-08-23
1. 是什么
xberg-io/html-to-markdown 是一个高性能、CommonMark 兼容的 HTML 到 Markdown 转换引擎。Rust 写核心,对外暴露 16 种语言绑定(Rust、Python、Node.js、WASM、Java、Go、C#、PHP、Ruby、Elixir、R、Dart、Kotlin Android、Swift、Zig、C ABI)。同一个 convert() 函数在每种语言里返回的结果是字节级别一致的——这是它最有辨识度的卖点。
背后的团队 Kreuzberg / Xberg 做的是"polyglot document intelligence"基础设施。这个仓库是他们产品线里的"HTML→Markdown"环节,与他们更大的"Xberg(101 格式内容智能引擎)""crawlberg(爬虫 + headless Chrome fallback)""alef(多语言绑定生成器)""liter-llm(165 提供商 LLM 客户端)"等仓库构成矩阵。仓库 MIT 协议。
2. 解决什么问题
市面上的 HTML→Markdown 转换库已经不少(html2text、Turndown、pandoc、markdownify…),但都有几类典型问题:
- 脏 HTML 失稳:未闭合标签、CDATA、自定义元素、错误实体、嵌套表格、混合编码——这些一上,输出就丢内容。
- 多语言绑定不一致:同一份 HTML 在 Python / Go / Node 里跑出来结果不一样。
- 没有元数据:丢掉了 Open Graph / Twitter Card / JSON-LD / microdata / RDFa 这类 head 里的结构化数据。
- 无法扩展:想自定义某些节点的输出方式?得 fork。
xberg-io/html-to-markdown 的差异化:
- 三级分层调度(byte scanner → DOM walker → html5ever repair):从最快的字节扫描开始,发现不合法就上升到 DOM 解析,发现还是不合法就交给 html5ever 修复。三档输出字节级一致。
- 真正脏 HTML 鲁棒:未闭合标签、CDATA、自定义元素、错误实体、嵌套表、混合编码都被默认处理,不用选解析策略。
- metadata 一并返回:head 中的 OG / Twitter / JSON-LD / microdata / RDFa / header hierarchy 在
convert()一次调用里一起拿回来。 - Djot 输出:除 CommonMark 外还能直接输出 Djot(轻量标记语言,typst / pandoc 都支持)。
- Visitor API:feature-gated,能在 AST 阶段转换输出结果而不必 fork。
- 19–116 MB/s(Wikipedia / mdream corpus 上),每个 PR 都有 per-group regression 阈值守门。
3. 快速安装
按你常用的语言挑一条(同一份 Rust 核心,结果一致):
3.1 Python
pip install html-to-markdown
3.2 Rust
cargo add html-to-markdown-rs
3.3 Node.js / TypeScript
npm install @xberg-io/html-to-markdown
# 或 WASM 版本
npm install @xberg-io/html-to-markdown-wasm
3.4 Go
go get github.com/xberg-io/html-to-markdown/packages/go/v3
3.5 Java(Maven Central)
<!-- groupId: io.xberg · artifactId: html-to-markdown -->
<!-- 具体 version 见仓库 packages/java/README.md -->
3.6 C#(NuGet)
dotnet add package XbergIo.HtmlToMarkdown
3.7 Ruby
gem install html-to-markdown
3.8 PHP(注意是原生 PHP 扩展,用 PIE 安装,不是 composer)
pie install xberg-io/html-to-markdown
3.9 Elixir
# mix.exs
{:html_to_markdown, "~> 3.6"}
3.10 R
install.packages("htmltomarkdown", repos = "https://xberg-io.r-universe.dev")
3.11 Dart / Flutter
dart pub add h2m
3.12 Kotlin(Android)
// Maven Central: io.xberg:html-to-markdown-android
// 详见 packages/kotlin-android/README.md
3.13 Swift(Swift Package Manager)
// 详见 packages/swift/README.md
3.14 Zig
// 详见 packages/zig/README.md
3.15 C / C++(FFI)
// 从 GitHub Releases 下载预编译 .so / .dll / .dylib
// 详见 crates/html-to-markdown-ffi
3.16 CLI
# 方式 1:通过 cargo
cargo install html-to-markdown-cli
# 方式 2:cargo-binstall
cargo binstall html-to-markdown-cli
# 方式 3:Homebrew
brew install xberg-io/tap/html-to-markdown
⚠️ 版本号 / 仓库路径核验提示:上述 crates.io / pypi / npm / maven central 的具体 version tag 与各 packages 子目录的最终 packages/python/README.md 等链接,建议安装前到对应 registries 查最新版本——本指南撰写时(2026-08-23)crates.io 与 npm 已确认可访问,但 version 数字未在仓库 README 主页直接列出,必须到各子 README 取最新。
4. 核心用法(Python 为例,其他语言 API 对应一致)
4.1 最简转换
from html_to_markdown import convert
html = """
<html>
<body>
<h1>标题</h1>
<p>这是 <strong>一段</strong> HTML。</p>
<table>
<thead><tr><th>A</th><th>B</th></tr></thead>
<tbody><tr><td>1</td><td>2</td></tr></tbody>
</table>
</body>
</html>
"""
md = convert(html)
print(md)
# 输出:
# # 标题
#
# 这是 **一段** HTML。
#
# | A | B |
# | --- | --- |
# | 1 | 2 |
4.2 拿 metadata(OG / Twitter / JSON-LD / header hierarchy)
from html_to_markdown import convert
html = '<html><head>...' # 含 OG / Twitter / JSON-LD 的 HTML
result = convert(html, extract_metadata=True)
print(result.markdown)
print(result.metadata.open_graph) # dict
print(result.metadata.twitter) # dict
print(result.metadata.json_ld) # list of dict
print(result.metadata.headers) # header hierarchy
实际 API 字段名请以
packages/python/README.md为准——本指南展示的是概念结构("convert 一次返回 markdown + 多个 metadata 通道")。
4.3 输出 Djot 而非 Markdown
md = convert(html, output_format="djot")
4.4 三档预处理预设
md_strict = convert(html, preset="strict") # 最严格
md_standard = convert(html, preset="standard") # 默认
md_lenient = convert(html, preset="lenient") # 最宽松
# 或自定义
md_custom = convert(html, preset={"drop": ["script", "style"], ...})
4.5 Visitor API(feature-gated,转换 AST 阶段)
from html_to_markdown import convert, visit
def rewrite(node, ctx):
if node.tag == "a" and node.attrs.get("href", "").startswith("http://"):
node.attrs["href"] = node.attrs["href"].replace("http://", "https://")
return node
md = convert(html, visitors=[rewrite])
4.6 inline 图片镜像(data URI / 远程图)
md = convert(html, inline_images=True, mirror_remote=True)
⚠️ mirror_remote=True 会触发网络 IO 拉图,务必在确认目标站点允许 / 自己有缓存策略时再用。
4.7 CLI 一次性转
html-to-markdown input.html > output.md
echo "<p>hello</p>" | html-to-markdown
5. 典型适用场景
- RAG / LLM 喂料前的清洗:把抓来的 HTML 文档转成结构干净的 Markdown,附 metadata 喂给检索 / 生成 pipeline。一次转换拿 markdown + OG + JSON-LD,省得再跑一次 head parser。
- 爬虫 / 内容聚合:搭配同团队
crawlberg,构成「HTTP 抓取 → 渲染兜底 → HTML→Markdown」的端到端方案。 - CMS / 文档站导出:从富文本编辑器存下来的脏 HTML 转 Markdown 入库;未闭合标签、CDATA、自定义元素都不用预处理。
- 跨语言微服务:上游 Python、下游 Go / Node / Rust,都对同一份 HTML 跑出字节级一致的 Markdown——做"内容契约"很合适。
- 整库批处理:19–116 MB/s 的吞吐适合一次性处理百万级 HTML 页面。
- 构建 Djot 文档:需要 typst / pandoc 链路时直接出 Djot,省一道转换。
不适用:
- "我只是想渲染 markdown 给人看"——直接用 markdown 渲染器即可,没必要从 HTML 反向;
- 需要 100% 保留 HTML 原结构(包括 inline style、复杂 attr)——Markdown 表达力有限,会丢;
- 不能跑 Rust 编译产物的环境(如果只允许纯 JS / 纯 Python,且性能要求在 MB/s 内——可以用 WASM / 纯 Python 备选,但性能会大幅下降)。
6. 坑与注意
- ⚠️ 不要把 Markdown 反向转 HTML 当主要用途:本仓库是单向 HTML→Markdown。要做反向,请看其他工具(如
markdownPython 库)。 - ⚠️ PHP 用户必须用 PIE,不能
composer require——它是 Rust 写的原生扩展(ext-php-rs),composer 装不上。 - ⚠️ GFM 表格的对齐与管道字符转义:库会按 CommonMark 规范转义
|;如果你的下游消费者有自定义的 GFM 解析器差异,最好先在 demo 页 docs.html-to-markdown.xberg.io/demo/ 验证。 - ⚠️
mirror_remote=True会阻塞:拉图是同步 IO,长跑建议先批量预下载再用data:URI 注入。 - ⚠️ 版本号在仓库 README 没集中列表:每个语言的最新 version 在对应
packages/<lang>/README.md里,安装前最好去对应 registry(PyPI / crates.io / npmjs / Maven Central / NuGet / RubyGems / Packagist / hex.pm / pub.dev)确认最新版本号,避免锁到过期版本。 - ⚠️ Djot 输出不是 Markdown:下游消费者如果是"只认 GFM / CommonMark"的渲染器(如 GitHub Markdown、Typora),把 Djot 当 Markdown 灌进去会渲染异常。
- ⚠️ C/C++ FFI 链接:跨语言 ABI 调用要自己管内存(Rust 侧返回的字符串生命周期),建议直接看
crates/html-to-markdown-ffi里的样例。 - ⚠️ CLI
brew tap命名空间:tap 完整名是xberg-io/tap/html-to-markdown,别忘了 owner。 - ⚠️ 仓库未列 benchmark 复现脚本:
19–116 MB/s on the Wikipedia/mdream corpus是 README 给的数字,但 corpus 与跑分脚本没在仓库主目录公开。要复测得自建测试集。
7. 与同类对比
- vs Turndown.js(Node):Turndown 是 Node 生态的事实标准,插件体系丰富;本仓库是 Rust 核心 + 多语言绑定,性能高一档,但 Node 插件生态刚起步。
- vs html2text(Python):html2text 古老、API 简单;本仓库在脏 HTML 鲁棒性 / metadata 提取 / 跨语言一致性三方面领先。
- vs pandoc:pandoc 是文档格式转换瑞士军刀,HTML→Markdown 只是它几十种格式之一;本仓库专攻这一条,API 更简单、性能更聚焦、绑定更多。
- vs Marked / markdown-it:这两个是 Markdown→HTML 的,方向相反,不可直接比较。
- vs
crawl4ai/markdownify:crawl4ai 偏 AI 抓取框架,HTML→Markdown 是它内部的一步;markdownify 是 Python 老牌库但更新慢。 - vs 同团队其他仓库:crawlberg 是爬虫、Xberg 是更广的文档智能(101 格式 + OCR)、alef 是绑定生成器、liter-llm 是 LLM 客户端——本仓库是矩阵里的"HTML→Markdown"节点,不是孤立工具。
8. 一句话推荐
如果你有多语言栈 / 脏 HTML / 要 metadata / 要高性能 HTML→Markdown,xberg-io/html-to-markdown 是当前(2026-08)最值得装的方案——同一份 Rust 核心、字节级一致输出、16 种语言绑定,省去你在不同语言里维护多套转换逻辑的麻烦。
参考链接:
- 仓库主页:https://github.com/xberg-io/html-to-markdown
- 文档站:https://docs.html-to-markdown.xberg.io
- 在线 Demo:https://docs.html-to-markdown.xberg.io/demo/
- Releases(含 FFI 预编译 .so/.dll/.dylib):https://github.com/xberg-io/html-to-markdown/releases
- Discord:https://discord.gg/xt9WY3GnKR
- 同团队矩阵:
- Xberg(101 格式内容智能引擎,MIT):https://github.com/xberg-io/xberg
- crawlberg(爬虫 + headless Chrome 兜底):https://github.com/xberg-io/crawlberg
- liter-llm(165 提供商 LLM 客户端):https://github.com/xberg-io/liter-llm
- tree-sitter-language-pack:https://github.com/xberg-io/tree-sitter-language-pack
- alef(多语言绑定生成器):https://github.com/xberg-io/alef
- 商业版:Xberg Pro(自托管内容智能后端,单容器)、Xberg Enterprise(K8s 上的分布式治理平台):https://xberg.io
⚠️ 核验状态:仓库主 README 中各语言安装命令与 crates.io / PyPI / npmjs / Maven Central / NuGet / RubyGems / Packagist / hex.pm / pub.dev 的可访问性已确认;具体 version tag(除 Elixir 的 ~> 3.6 出现在 README 显式位置外)未在主 README 集中列出,建议安装前到对应 registry 取最新版本号。