
本文详细介绍如何利用 pymupdf(fitz)高效提取 pdf 书籍的结构化目录,涵盖标准 toc 解析、基于字体大小的启发式标题识别方法,并提供可直接运行的代码示例与关键注意事项。
本文详细介绍如何利用 pymupdf(fitz)高效提取 pdf 书籍的结构化目录,涵盖标准 toc 解析、基于字体大小的启发式标题识别方法,并提供可直接运行的代码示例与关键注意事项。
在实际处理电子书或技术文档时,自动提取目录(Table of Contents, TOC)是构建知识图谱、实现跳转导航或生成摘要的关键前提。但需明确:PDF 本身不是结构化格式,其“目录”是否可提取,取决于 PDF 是否内嵌了逻辑书签(即 Acrobat-style outline)。幸运的是,PyMuPDF 提供了 Document.get_toc() 方法,可直接读取该元数据——这是最准确、最推荐的首选方案。
✅ 方法一:使用内置书签提取标准 TOC(推荐)
前提是 PDF 在生成时已嵌入书签(如由 LaTeX hyperref、Word 导出或专业排版工具生成):
import fitz # pip install PyMuPDF
def extract_toc_from_bookmarks(pdf_path):
doc = fitz.open(pdf_path)
toc = doc.get_toc() # 返回 list,每个元素为 [level, title, page_number]
doc.close()
return toc
# 示例输出:[[1, "Introduction", 1], [2, "Background", 3], [1, "Methodology", 5]]
toc = extract_toc_from_bookmarks("book.pdf")
for level, title, page in toc:
indent = " " * (level - 1)
print(f"{indent}• {title} (p.{page})")
⚠️ 注意:若 toc 为空列表 [],说明该 PDF 未嵌入书签,此时需启用备用策略。
? 方法二:基于字体大小启发式识别标题(适用于无书签 PDF)
当 PDF 仅含视觉排版(如扫描件除外的常规文字 PDF),可通过分析文本块的字体大小分布定位标题。核心思路是:
- 统计全文所有文本块的字体大小;
- 计算众数(mode)作为正文基准字号;
- 将显著大于基准字号(如 ≥ 基准 + 2pt)的文本视为标题候选;
- 结合位置(如居中、段首缩进少)、样式(加粗)进一步过滤。
import fitz
from collections import Counter
def heuristic_toc_extraction(pdf_path, min_level_size_diff=2.0, max_pages=20):
doc = fitz.open(pdf_path)
font_sizes = []
text_blocks = []
# 遍历前若干页(避免全书扫描耗时)
for page_num in range(min(max_pages, doc.page_count)):
page = doc[page_num]
blocks = page.get_text("dict")["blocks"]
for b in blocks:
if "lines" in b:
for line in b["lines"]:
for span in line["spans"]:
font_size = round(span["size"], 1)
font_sizes.append(font_size)
text_blocks.append({
"text": span["text"].strip(),
"size": font_size,
"page": page_num + 1,
"flags": span["flags"] # 位掩码:4=bold, 8=italic
})
if not font_sizes:
return []
# 计算正文基准字号(众数)
size_counts = Counter(font_sizes)
base_size = size_counts.most_common(1)[0][0]
# 筛选标题:字号显著更大 + 非空 + 长度适中(排除页眉页脚)
candidates = [
tb for tb in text_blocks
if tb["size"] >= base_size + min_level_size_diff
and len(tb["text"]) > 5
and len(tb["text"]) <h3>? 关键注意事项与优化建议</h3>
- 书签优先:始终先尝试 get_toc(),它是语义级、零误差的权威来源;启发式方法仅为降级方案。
- 字体大小非绝对:不同 PDF 的字号体系差异大(如学术论文常用 10–12pt 正文,而教材可能用 14pt),建议动态计算基准而非硬编码阈值。
- 规避干扰项:封面标题、页眉页脚、图表标题易误判,需通过正则匹配(如 r'^\d+\.\s+')、上下文位置或 OCR 后 NLP 分类进一步过滤。
- 性能考量:对超长 PDF(>1000页),限制分析页数(如仅前 50 页),因目录通常集中于开头。
- 增强鲁棒性:可结合 page.get_text("blocks") 获取文本块坐标,识别居中/左对齐模式;或调用 fitz.Page.get_links() 辅助定位跳转锚点。
综上,PyMuPDF 是目前 Python 生态中处理 PDF 目录提取最成熟的选择:get_toc() 解决“有结构”的场景,启发式分析覆盖“无结构但排版规范”的常见情况。二者结合,即可应对绝大多数电子书自动化解析需求。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











