跳到主要内容

Docling

Docling 是 IBM Research 开源的企业级文档解析工具,专注于将各类文档(PDF、Word、PowerPoint等)转换为结构化格式,特别适合企业知识管理和RAG应用场景。

🌟 核心特性

  • 多格式支持:PDF、DOCX、PPTX、HTML等多种格式
  • 结构化输出:JSON、Markdown、DocBook等格式
  • 企业级质量:高准确率,适合生产环境
  • 版面分析:精确识别文档结构和层级
  • 表格提取:高质量的表格识别和转换
  • 元数据提取:提取作者、标题、日期等元信息
  • 批量处理:支持大规模文档批处理
  • 可扩展性:插件化架构,易于扩展

📦 安装与使用

快速安装

# 使用 pip 安装
pip install docling

# 安装完整版本(包含OCR)
pip install docling[ocr]

# 从源码安装
git clone https://github.com/DS4SD/docling.git
cd docling
pip install -e .

命令行使用

# 转换单个文档
docling convert document.pdf

# 指定输出格式
docling convert document.pdf --format markdown

# 批量转换
docling convert ./documents/*.pdf --output ./output

# 提取元数据
docling extract document.pdf --metadata

Python API

from docling import DocumentConverter

# 创建转换器
converter = DocumentConverter()

# 转换PDF
result = converter.convert("document.pdf")

# 获取Markdown
markdown = result.document.export_to_markdown()
print(markdown)

# 获取JSON
json_output = result.document.export_to_json()

# 获取文档结构
for element in result.document.elements:
print(f"类型: {element.type}, 内容: {element.text[:50]}")

🏗️ 技术架构

graph TB
A[输入文档] --> B{格式判断}
B -->|PDF| C[PDF解析器]
B -->|DOCX| D[DOCX解析器]
B -->|PPTX| E[PPTX解析器]
C --> F[版面分析]
D --> F
E --> F
F --> G[元素识别]
G --> H[结构化组装]
H --> I[格式转换]
I --> J[输出结果]

G -->|文本/标题/段落| G1[文本元素]
G -->|表格| G2[表格元素]
G -->|图片| G3[图片元素]
G -->|列表| G4[列表元素]

核心组件

  • 解析器层: 支持多种文档格式的底层解析
  • 分析层: 版面分析和结构识别
  • 转换层: 格式转换和输出生成
  • 扩展层: 插件和自定义处理

🎯 应用场景

1. 企业知识库构建

from docling import DocumentConverter
import json

def build_knowledge_base(doc_path):
"""构建企业知识库"""
converter = DocumentConverter()
result = converter.convert(doc_path)

# 提取结构化信息
knowledge = {
"title": result.document.metadata.get("title"),
"author": result.document.metadata.get("author"),
"date": result.document.metadata.get("date"),
"content": [],
"tables": [],
"images": []
}

# 按类型组织内容
for element in result.document.elements:
if element.type == "heading":
knowledge["content"].append({
"type": "section",
"level": element.level,
"title": element.text
})
elif element.type == "paragraph":
knowledge["content"].append({
"type": "text",
"content": element.text
})
elif element.type == "table":
knowledge["tables"].append({
"data": element.to_dataframe().to_dict(),
"caption": element.caption
})
elif element.type == "image":
knowledge["images"].append({
"path": element.image_path,
"caption": element.caption
})

return knowledge

2. RAG数据准备

from docling import DocumentConverter

def prepare_rag_documents(doc_path, chunk_size=500):
"""为RAG准备文档数据"""
converter = DocumentConverter()
result = converter.convert(doc_path)

chunks = []
current_chunk = ""
current_metadata = {}

for element in result.document.elements:
# 按标题分块
if element.type == "heading":
if current_chunk:
chunks.append({
"text": current_chunk,
"metadata": current_metadata.copy()
})
current_chunk = f"# {element.text}\n\n"
current_metadata = {
"section": element.text,
"level": element.level
}

# 添加内容
elif element.type == "paragraph":
current_chunk += element.text + "\n\n"

# 达到块大小限制
if len(current_chunk) >= chunk_size:
chunks.append({
"text": current_chunk,
"metadata": current_metadata.copy()
})
current_chunk = ""

# 添加最后一块
if current_chunk:
chunks.append({
"text": current_chunk,
"metadata": current_metadata
})

return chunks

3. 文档对比分析

from docling import DocumentConverter
from difflib import SequenceMatcher

def compare_documents(doc1_path, doc2_path):
"""对比两个文档"""
converter = DocumentConverter()

# 转换两个文档
doc1 = converter.convert(doc1_path)
doc2 = converter.convert(doc2_path)

# 提取文本
text1 = doc1.document.export_to_text()
text2 = doc2.document.export_to_text()

# 计算相似度
similarity = SequenceMatcher(None, text1, text2).ratio()

# 结构对比
structure_diff = {
"doc1_sections": len([e for e in doc1.document.elements if e.type == "heading"]),
"doc2_sections": len([e for e in doc2.document.elements if e.type == "heading"]),
"doc1_tables": len([e for e in doc1.document.elements if e.type == "table"]),
"doc2_tables": len([e for e in doc2.document.elements if e.type == "table"]),
}

return {
"text_similarity": similarity,
"structure_diff": structure_diff
}

4. 批量文档处理

from docling import DocumentConverter
from pathlib import Path
import json

def batch_process_documents(input_dir, output_dir):
"""批量处理文档"""
converter = DocumentConverter()

input_path = Path(input_dir)
output_path = Path(output_dir)
output_path.mkdir(exist_ok=True)

# 支持的文件格式
patterns = ["*.pdf", "*.docx", "*.pptx"]

results = []

for pattern in patterns:
for doc_file in input_path.glob(pattern):
try:
print(f"处理: {doc_file.name}")

# 转换文档
result = converter.convert(str(doc_file))

# 保存Markdown
md_file = output_path / f"{doc_file.stem}.md"
with open(md_file, "w", encoding="utf-8") as f:
f.write(result.document.export_to_markdown())

# 保存JSON元数据
meta_file = output_path / f"{doc_file.stem}_meta.json"
with open(meta_file, "w", encoding="utf-8") as f:
json.dump(result.document.metadata, f, indent=2)

results.append({
"file": doc_file.name,
"status": "success",
"pages": result.document.metadata.get("pages", 0)
})

print(f"完成: {doc_file.name}")

except Exception as e:
results.append({
"file": doc_file.name,
"status": "error",
"error": str(e)
})
print(f"错误 {doc_file.name}: {e}")

# 保存处理报告
report_file = output_path / "processing_report.json"
with open(report_file, "w", encoding="utf-8") as f:
json.dump(results, f, indent=2)

return results

🔧 高级配置

自定义转换器

from docling import DocumentConverter
from docling.datamodel import ConversionOptions

# 创建自定义配置
options = ConversionOptions(
# PDF配置
pdf_backend="pdfium", # pdfium/pypdfium2/pdfplumber
extract_images=True,
extract_tables=True,

# OCR配置
ocr_enabled=True,
ocr_language="chi_sim+eng", # 中英文OCR

# 表格配置
table_parser="camelot", # camelot/tabula
table_areas="stream", # stream/lattice

# 输出配置
preserve_layout=True,
include_metadata=True
)

# 使用自定义配置
converter = DocumentConverter(options=options)
result = converter.convert("document.pdf")

表格处理

def extract_all_tables(doc_path):
"""提取所有表格"""
converter = DocumentConverter()
result = converter.convert(doc_path)

tables = []
for element in result.document.elements:
if element.type == "table":
# 转为DataFrame
df = element.to_dataframe()

tables.append({
"page": element.page,
"caption": element.caption,
"data": df,
"markdown": element.to_markdown(),
"html": element.to_html()
})

return tables

插件扩展

from docling import DocumentConverter
from docling.plugins import Plugin

class CustomPlugin(Plugin):
"""自定义处理插件"""

def process_element(self, element):
"""处理每个元素"""
if element.type == "paragraph":
# 自定义段落处理
element.text = element.text.strip()

return element

# 注册插件
converter = DocumentConverter()
converter.register_plugin(CustomPlugin())

result = converter.convert("document.pdf")

📊 性能对比

特性DoclingMinerUMarkerPyMuPDF
多格式支持⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
结构化输出⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
企业级质量⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
处理速度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
易用性⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

💡 最佳实践

  1. 文档预处理

    # 检查文档质量
    result = converter.convert("document.pdf")
    quality_score = result.metadata.get("quality_score", 0)

    if quality_score < 0.7:
    # 启用OCR
    converter.options.ocr_enabled = True
    result = converter.convert("document.pdf")
  2. 内存优化

    # 流式处理大文档
    converter = DocumentConverter(streaming=True)

    for page_result in converter.convert_stream("large_doc.pdf"):
    process_page(page_result)
    # 逐页处理,减少内存占用
  3. 错误处理

    from docling.exceptions import ConversionError

    try:
    result = converter.convert("document.pdf")
    except ConversionError as e:
    print(f"转换失败: {e}")
    # 降级处理
    result = fallback_conversion("document.pdf")
  4. 输出格式选择

    # 根据用途选择格式
    markdown = result.document.export_to_markdown() # 文档展示
    json_data = result.document.export_to_json() # 数据分析
    docbook = result.document.export_to_docbook() # 出版流程

📚 资源链接

⚠️ 注意事项

  • 首次运行会下载必要的模型
  • OCR功能需要额外安装tesseract
  • 大文件处理可能需要较多内存
  • 某些格式需要安装额外依赖
  • 商业使用需注意license

🆚 适用场景

选择 Docling 当:

  • 需要处理多种文档格式
  • 构建企业级知识管理系统
  • 需要高质量的结构化输出
  • 准备RAG应用的数据
  • 需要可靠的生产环境解决方案

选择其他工具当:

  • 只处理PDF → Marker/MinerU
  • 追求极致速度 → Marker
  • 需要最高准确率 → MinerU
  • 简单场景 → PyMuPDF

🔄 更新日志

  • 2024.08: v1.0.0 - 正式发布
  • 2024.06: Beta版本 - 添加PPTX支持
  • 2024.04: Alpha版本 - 首次公开