尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Docling实战:从PDF到结构化Markdown与JSON的文档解析指南

发布时间:2026/9/26 14:47:47

资讯中心
01
ARTICLE

Docling实战:从PDF到结构化Markdown与JSON的文档解析指南

Docling实战:从PDF到结构化Markdown与JSON的文档解析指南
做文档处理这些年我越来越觉得PDF这玩意儿就是个“格式牢笼”。表面看是个文件里面文字表格图片都摆得整整齐齐可真要把它里面的内容抽出来用能让人头疼到怀疑人生。这个月我集中测了一款叫docling的开源文档解析工具GitHub上热度涨得很快做RAG、文档问答和知识库的同行都在安利所以我把一周多的实测过程和踩坑记录整理出来给想用文档解析做信息抽取或者自动化处理的朋友做个参考。1. 文档解析这件事痛点比你想的多1.1 从一道“格式毒药”说起先说说我们平时遇到的坑。很多人觉得PDF转Word、PDF转文本是再简单不过的事随便找个在线工具点一下转换完事。但只要你处理过几十份真实业务文档就知道这里面的水深得很。最典型的问题是“文字顺序错乱”PDF里两栏排版的论文转出来之后左右两边的内容搅在一起像一团乱麻表格稍微复杂一点转出来要么挤成一堆要么直接变成一行一行的残废文本还有那些带脚注、眉页、页码的合同和报告转完之后这些标注全混到正文里了。为什么会这样因为PDF本质上不是一种“文档编辑格式”它存的是每个字符在页面上的坐标位置有点像一张拍好的照片而不是排版原稿。机器拿到PDF之后如果想从里面读出“这段是标题那段是正文这个表格是两行三列”它必须自己去推断。传统转换工具的思路大多是“按坐标抓字拼串”效果自然就看运气了。我见过有同行用正则去PDF里抽表格遇到稍微规整的还行遇到跨页的、带样式的基本就是灾难现场。1.2 Docling的思路先读懂文档再输出结构docling这个项目给我的第一印象是它换了一条路不是“提取文字”而是“理解文档”。你要拿一份PDF给它它会先对整个页面做布局分析识别出哪个区域是标题、哪个区域是正文、哪个区域是表格、哪个区域是图片然后再把这些区域里的内容按照阅读顺序组织起来最终输出成结构化的Markdown或者JSON。也就是说它做了一个“人眼看文档”的动作先看懂版式再翻译成机器能直接用的结构。docling是IBM开源出来的目前支持PDF、Word、PPT、Excel、HTML和图片等常见输入格式输出上最常用的是Markdown和JSON两种。对于做知识库、做文档问答、做自动化归档的小伙伴来说它解决了一个核心问题文档里的信息不再是“人知道但机器拿不到”的状态而是可以变成带层级、带语义、带坐标的数据。这篇文章后面我会重点讲PDF场景因为这个最能反映一个文档解析工具的真实水准。2. 安装部署与前置依赖比想象中省事2.1 三步完成环境准备docling用起来的前置条件不复杂核心就是Python环境加pip安装。建议你用一个干净的虚拟环境避免和项目里其他依赖冲突。我第一次装的时候直接用全局环境结果把opencv的版本搞乱了后面排查了半天才意识到是环境问题。python -m venv .venv source .venv/bin/activate pip install docling[ocr]这里有个小细节要说明docling是核心包[ocr]这个扩展会额外帮你装好OCR相关的依赖默认带的是EasyOCR。如果你不装OCRdocling也能处理数字原生的PDF但遇到扫描件、图片型PDF就会束手无策。我个人的建议是哪怕暂时用不到也先把OCR扩展装上因为业务的文档类型永远是变化的等真遇到一份没法复制文字的扫描合同时再补装反而会耽误事。安装完成后你在终端里直接敲docling --help就能看到命令帮助说明装好了。如果是在Python脚本里用导入DocumentConverter的时候没有报错环境就算准备完成了。整个过程从零到能用实测十分钟以内。2.2 OCR引擎该不该装装哪个docling底层的OCR实现有两种比较主流的选法一种是它默认集成的EasyOCR另一种是Tesseract。这两者没有绝对的好坏取决于你的使用场景。对比项EasyOCRTesseract安装方式跟随docling[ocr]自动安装需要在系统里单独装Tesseract程序中文支持内置效果不错需要额外下载中文语言包识别精度对清晰文档较高对旧版扫描件和特殊字体更稳资源占用加载模型耗内存较多相对轻量CPU上也能跑配置方式在Python里设EasyOcrOptions在Python里设TesseractOcrOptions我自己的实测感受是如果文档是中文扫描件EasyOCR开箱即用的体验会更好如果处理的是英文历史文献、老报纸这种对比强烈的黑白扫描件Tesseract有时候反而更能抗噪。你完全可以在代码里根据文件类型动态选择OCR引擎docling的Pipeline选项里预留了灵活的切换接口。2.3 首次运行前心里有个底第一次跑docling的时候你可能会有种“卡住”的错觉其实它在下载模型。docling核心的布局分析模型和表格结构模型会从HuggingFace模型仓库拉到本地缓存目录一般在~/.cache/huggingface下。整个过程取决于网络状况快的话一两分钟慢的话可能要等一会儿。如果发现几百M的模型下不动可以提前把缓存目录共享到内网或者设置HF_HOME环境变量指向你指定的模型目录。另外关于硬件配置docling在CPU上确实能跑但速度和体验完全两回事。我用一台普通的MacBook Pro处理一份40页的PDFCPU模式下大概要一分钟左右换到带CUDA的GPU机器同一个文件压缩到十几秒。如果你的项目里文档量很大强烈建议用GPU环境。内存方面普通文档8GB够用但如果是高分辨率扫描件开了OCR16GB会比较稳。3. 核心实操从PDF到结构化Markdown3.1 一行命令快速上手docling的命令行入口做得非常简单开箱即用这个感受非常强。不用写任何代码就能把一个PDF转成Markdown和JSON。docling demo.pdf --to markdown --output ./out执行完之后./out目录下会生成两个文件demo.md和demo.json。demo.md是给人看的Markdown文本里面标题、表格、列表结构都是规整的demo.json是给程序用的结构化数据。我第一次处理一份带复杂表格的年度报告时看到Markdown里表格被完整还原成markdown表格格式说实话还是挺惊喜的——这比传统工具直接把表格拍平成散文字强太多了。如果你处理的PDF是扫描件记得加上--ocr参数如果表格比较密集还可以用--table-mode accurate让表格识别走更精细的模式。官方默认的模式是快速的在表格简单时速度优先但表格复杂的时候我又测过用accurates模式漏格和错格的情况明显减少。3.2 用Python API定制你的转换流程命令行适合临时用用真正集成到业务系统里还是走Python API更灵活。docling的接口设计不算复杂核心就是DocumentConverter这个类。from docling.document_converter import DocumentConverter converter DocumentConverter() result converter.convert(demo.pdf) doc result.document # 导出Markdown with open(demo.md, w, encodingutf-8) as f: f.write(doc.export_to_markdown()) # 导出JSON with open(demo.json, w, encodingutf-8) as f: import json json.dump(doc.export_to_dict(), f, ensure_asciiFalse, indent2)这段代码几分钟就能跑通。我实际开发的时候还会在转换前后加一些统计信息和异常处理比如记录converter.convert()的耗时、返回状态等方便排查问题。值得留意的是convert()方法返回的Document对象里不仅包含Markdown导出结果还保留着整个文档的层级结构、阅读顺序和布局元素信息。你要做信息抽取的时候不需要自己再写一堆正则去猜哪里是标题直接从JSON里按元素类型过滤就行。3.3 表格识别这是它的强项但也不是神表格解析是docling的招牌功能之一。它内部用了专门的表格结构模型能从PDF页面上把表格边框、单元格、跨行跨列的信息抠出来还原成带有行列语义的结构化表格。我拿一个七列十五行的数据表来测它能准确把表头识别出来文本内容也能按单元格对号入座Markdown渲染出来基本和原版一致。不过把丑话说在前面它面对那种“反人类”的复杂表格时还是会翻车。比如带合并单元格的复杂表头、嵌套表格、跨页断开的表格偶尔会出现格子错位、内容串行。我的处理习惯是表格数量少但精度要求高的文档转完必看一遍Markdown对一致性要求极其严格的数据比如财报里的数字表再加一步程序校验而不是盲目信任输出。如果你在代码里想调整表格识别级别可以通过Pipeline选项设置from docling.document_converter import DocumentConverter, PdfFormatOption from docling.datamodel.base_models import InputFormat from docling.datamodel.pipeline_options import PdfPipelineOptions pipeline_options PdfPipelineOptions() pipeline_options.table_mode accurate # 或者 fast converter DocumentConverter( format_options{ InputFormat.PDF: PdfFormatOption(pipeline_optionspipeline_options) } )3.4 JSON输出给下游开发者的“富矿”可能很多朋友第一次用docling只盯着Markdown看把JSON当成了副产品。实际上JSON才是真正的宝贝。docling输出的JSON里文档被拆成了带类型的元素列表比如title、paragraph、table、list、code每个元素还附带bbox坐标框信息以及它在页面阅读顺序中的位置。这意味着你完全可以基于这份JSON把一份PDF“翻译”成一份按阅读顺序排列的内容索引。这个特性在RAG场景里太好用了。传统做法是拿PDF转出的一堆文本直接塞进向量库但往往噪音太大、结构丢失。用docling的JSON处理后你可以按元素粒度做切片给标题、段落、表格分别打标签再灌进向量库。检索的时候用户问表里的数据你直接命中表格元素问某个标题下的内容你命中最接近的标题块。这些在之前都是要花大量精力去清洗才能做到的效果。4. 进阶玩法与性能调优4.1 批量转换让脚本替你做脏活真正落地的时候没人会一份一份手动跑命令行都是直接上一个目录扔进去批量处理。批量转换的代码不复杂但有几个细节值得关注。import os from pathlib import Path from docling.document_converter import DocumentConverter converter DocumentConverter() input_dir Path(./pdfs) output_dir Path(./output) output_dir.mkdir(exist_okTrue) for pdf_file in input_dir.glob(*.pdf): try: result converter.convert(str(pdf_file)) out_md output_dir / f{pdf_file.stem}.md out_md.write_text(result.document.export_to_markdown(), encodingutf-8) print(f处理完成: {pdf_file.name}) except Exception as e: print(f处理失败: {pdf_file.name}, 原因: {e})这里第一个坑是内存问题。如果一次性处理上千份PDF持续调用convert()可能会让内存占用慢慢增长。我实际验证后发现长时间批量跑任务时最好每处理完一批就gc.collect()强制回收一次或者干脆把进程拆成按固定数量文档处理的子任务处理完一批自动重启。第二个坑是断点续跑。批量任务跑一半挂了是很正常的事情输出文件已存在就直接跳过能省下一大半重试时间。4.2 自定义Pipeline按需取舍加速docling默认的处理流程是“布局分析表格识别OCR全开”但很多场景下你并不需要每一样都跑。比如你的PDF是纯文字报表没有复杂版面那布局分析可以保留默认如果是扫描件但没有表格就可以把表格识别关掉只保留OCR和文本抽取速度能提升不少。Pipeline的定制入口在上面已经见过PdfPipelineOptions里除了table_mode还有几个常用的开关pipeline_options.do_ocr True # 是否启用OCR pipeline_options.do_table_structure False # 是否启用表格结构识别 pipeline_options.do_code False # 是否识别代码块我第一次优化一个扫描合同批量解析任务时把表格结构识别关掉之后处理速度几乎快了一倍。所以建议你拿到一批新文档时先抽一两份样本看看文档里到底有哪些元素再决定Pipeline的开关组合。工具是死的需求是活的这比盲目追求最高精度划算得多。4.3 性能对比与调参经验性能这个事做技术的都关心。我同一份126页的PDF分别在CPU和GPU上跑了一遍结果很直观CPU耗时大约3分半GPU耗时不到1分钟。如果你的机器没有GPU但又要处理大量扫描件建议先优化一个参数降低输入图片的分辨率。OCR处理高分辨率扫描件时每页的图像解压和预处理非常消耗CPU把扫描分辨率控制在150dpi到200dpi之间清晰度足够速度却会好看很多。还有一个容易被忽略的点是并发线程数。docling内部用了并行处理默认参数在某些容器环境下可能不合理。如果发现CPU占用一直上不去或者反过来内存一直在涨可以在代码里看看进程实际起的线程数太高就手动限制一下。我在一个4核CPU的云主机上跑任务时把并行度调到2到3整体吞吐反而比默认全开更稳定。5. 常见问题排查实录5.1 OCR中文识别不出来怎么办这是我在测试群和评论区看到最多的问题。很多人装了docling去转中文扫描件结果输出里中文变成了乱码或直接消失。原因多半是OCR引擎的语言参数没有设置。docling默认的EasyOCR语言列表里包含英文但中文需要你显式添加。from docling.datamodel.pipeline_options import EasyOcrOptions ocr_options EasyOcrOptions(lang[en, ch_sim]) pipeline_options.ocr_options ocr_options如果你用的是Tesseract语言参数是eng和chi_sim同时要确保系统里已经安装了对应的语言包。这个参数加好之后中文识别率会有质的变化。另外扫描件的质量也很影响OCR效果我试过一份对比度很差的快递底单加对比度之后识别率立竿见影。如果原图已经糊成一团换任何引擎都救不回来。5.2 表格从中间开始乱掉表格整体没问题但到了中间或者跨页的位置就开始错位、串行这个问题我在处理长表格时也遇到过。通常原因是PDF里表格被分页拆开了docling在识别跨页表格时需要把上下两段拼接起来一旦表头或边界判断有一点偏差后面的单元格就全乱了。处理这类文档我的经验是先试试切换table_mode从fast切到accurate表格结构模型有更高概率把表头与数据行对应正确如果PDF本身是扫描件先跑一遍OCR再进表格识别比直接看扫描图识别强很多。还有一种情况是文档里某些表格本身就没有明显边框线这种“无框表格”机器识别难度本就很高别把期望拉满必要时刻用人工复核收尾。5.3 转换速度慢、内存涨得快速度慢通常集中在两个环节一是大量扫描件走OCR二是超大文档一次性转换。拿我那份300页的行业报告来说直接整本丢进docling中途内存一度逼近极限属实压力拉满。解决办法很朴素拆分。从源头把PDF按章节拆成几十个独立小文件再逐一转换最后合并Markdown。这样节省内存更重要的是哪怕中间某个文件失败了重跑一个片段就行不用全量再来。另外内存持续上涨还有一个隐蔽原因批量循环里不断创建新的DocumentConverter实例。正确做法是不管处理多少文件都复用一个converter实例避免重复加载模型、反复开辟内存。5.4 离线环境模型加载不了如果你在内网部署没有外网权限首次运行docling大概率会卡在模型下载。这里的核心思路是“提前把模型准备好让程序走本地加载”。第一步在一台能联网的同架构机器上跑一次转换把~/.cache/huggingface目录整体打包拷到目标机器第二步在目标机器上设置环境变量HF_HOME指向解压后的目录让docling启动时直接读本地模型。export HF_HOME/data/huggingface_cache export HF_HUB_OFFLINE1设置好后docling不会再尝试联网模型加载只在本地缓存里找。需要注意的是docling版本升级后模型缓存的结构可能略有变化离线部署时尽量保持目标机器的包版本和模型来源机器一致不容易踩“版本不匹配”的坑。这个方法也适用于有网络隔离要求的企业内部环境操作起来很实用。这几天实测下来我对docling最大的感受是它不是在帮你“转换文件”而是真的在尝试让机器“看懂”文档。它并不完美复杂表格、老旧扫描件照样会翻车但只要搭配好OCR开关、表格模式、批量拆分这几招它完全能撑起一条自动化的文档处理流水线。最后分享一个自己的小技巧文档页数多的时候不要整本丢进去先按章节拆分再逐段交给docling速度会快很多出问题也只影响局部。希望这篇实测记录能帮你少踩几个坑让文档解析这件事不再那么“玄学”。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。