为什么将 PDF 转换为 Markdown 比看起来更难
Source: Dev.to
介绍
当人们听到“PDF 转 Markdown”时,往往觉得这只是一个简单的文本转换任务。
实际上,处理 PDF——尤其是当你在乎其结构时——是任何开发者工具都可能遇到的最棘手的解析问题之一。
我在文档和 LLM 工作流中屡次遇到这个问题,于是我构建了一个工具来解决它。在本文中,我将深入探讨为何这个问题如此困难,通常会出现哪些错误,以及结构感知的流水线如何让 Markdown 输出更易用。
PDF 结构基础
PDF 文件并不像 HTML 或 Markdown 那样将段落、标题或表格编码为高级概念。相反,它包含:
- 在特定 (x, y) 坐标绘制文本的指令
- 用于图像、形状、路径的绘图指令
- 变换矩阵
- 可选元数据
该格式中没有“段落”对象。所有结构必须通过以下方式推断:
- 几何邻近性
- 字体大小和样式
- 对齐和分组
这使得 PDF → Markdown 的转换在本质上不同于简单的“文本提取”。
PDF 类型
本地 PDF(文本对象)
许多 PDF 包含可以直接读取的真实文本对象:
- 可通过 PyMuPDF 或 pdf.js 等库提取
- 包含每个跨度的位置信息(边界框)
- 保留字体、字形和布局顺序
这是结构分析的最佳情况。
扫描 PDF(光栅图像)
有些 PDF 仅仅是一堆光栅图像(例如扫描件):
- 完全没有文本对象 → 所有内容必须通过 OCR 获得
- 不保留布局元数据
这类文件缺少块信息,需要依据视觉线索重建文档结构。检测应采用哪种路径是首要步骤;如果把扫描文档和本地文档一视同仁,往往会导致糟糕的输出。
常见失败模式
-
平面文本转储 – 许多 PDF → Markdown 工具仅按阅读顺序转储文本,导致:
- 行断点出现在错误位置
- 段落边界丢失
- 列表被破坏
- 缺少语义分组
输出可能是 Markdown,但很少易于使用。
-
对原生 PDF 进行不必要的 OCR – 对已经包含文本的 PDF 进行 OCR:
- 引入噪声
- 丢失格式
- 增加不必要的预处理
-
孤立的图像 – 在不知道图像在文流中应放置位置的情况下提取图像会失去意义,因为在 Markdown 中图像的放置很重要。
Source: …
布局感知管道
关键的认识是将 PDF 视为一组 布局块,每个块包含:
- 边界框
- 页码
- 内容类型(文本 / 图像 / 表格 / 代码)
该管道随后:
- 按升序
(page, y, x)对所有块进行排序。 - 将跨度合并为段落,再将段落合并为更高级别的结构。
- 基于几何启发式方法重建列表和表格。
- 在相对于文本块的最佳位置插入图像。
这种方法并不会神奇地发现隐藏的语义,但它能够生成:
- 可读的 Markdown
- 不需要数小时的清理工作
- 相比平面提取更好地保留结构关系
处理扫描版 PDF
当缺少原生文本块时,所有块必须从视觉内容中派生:
- 布局信息丢失 → OCR 提供文本。
- 块由视觉区域检测构建。
这是一种与原生解析根本不同的过程,必须按此对待。工具会自动检测扫描版 PDF 并将其路由至基于 OCR 的提取。虽然 OCR 结果本质上比原生文本提取更嘈杂,但它们仍能提供可用的 Markdown,而普通解析往往会失败。
表格
PDF 并未显式表示表格。你需要从以下方面推断结构:
- 列对齐
- 行接近度
- 网格线(如果存在)
标准 Markdown 表格无法表达 rowspan/colspan。对于复杂布局,通常更倾向于使用 HTML 表格作为备选方案。
列表
项目符号和缩进仅是视觉提示。重建嵌套列表需要:
- 项目符号模式检测
- 相对缩进比较
- 跨行分组
当仔细实现时,这些启发式方法能够相当有效。
代码块
代码通常可以通过以下方式识别:
- 等宽字体
- 一致的垂直间距
- 缺少列表/表格标记
准确地区分代码可以提升技术文档输出的可读性。
限制
从 PDF 到 Markdown 的完美往返在严格意义上是不可能的:
- PDF 没有语义文档模型。
- OCR 本身存在错误率。
- 布局推断是基于启发式方法的。
然而,“足够好”的解决方案应满足以下条件:
- Markdown 可读。
- 结构元素未被破坏。
- 图像和表格不会孤立。
- 需要的手动清理最少。
对于文档编写、笔记或 LLM 工作流而言,这远比像素级完美保真更为重要。
结论
PDF 的设计初衷是用于打印和视觉保真,而不是语义复用。将其转换为 Markdown 本质上是一个翻译问题——从几何到结构。结构感知的流水线使这种转换比朴素的提取更可靠,并且对原生 PDF 和扫描 PDF 的稳健处理对于实际使用至关重要。
如果您想看到这些想法的实际实现,请查看 。欢迎提供反馈和边缘案例示例。