You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python提取PDF书籍的章节目录(含子标题)

Python提取PDF结构化目录(含章节及子标题)

一、提取PDF内置书签(Outline)(优先推荐)

正规出版的PDF书籍大多会内置结构化书签目录,这是最准确的提取方式。PyMuPDF(fitz)支持直接获取书签的层级关系,之前可能没用到这个核心功能。

import fitz  # PyMuPDF

def extract_outline(pdf_path):
    doc = fitz.open(pdf_path)
    # 获取书签列表,格式为[(层级, 标题, 页码), ...]
    outline = doc.get_toc()
    doc.close()
    
    # 格式化层级结构输出
    formatted_toc = []
    for level, title, page in outline:
        indent = "    " * (level - 1)
        formatted_toc.append(f"{indent}{level}. {title} (页码: {page})")
    
    return "\n".join(formatted_toc)

# 使用示例
pdf_path = "your_book.pdf"
print(extract_outline(pdf_path))

说明:get_toc()返回的每个元素第一个值就是层级(1为一级章节,2为子标题,以此类推),通过缩进可直观展示目录结构。

二、无内置书签时,从页面文本提取目录

如果PDF没有内置书签,只能从目录页文本中识别,核心是利用文本的字体大小、缩进位置区分章节层级。

import fitz

def extract_toc_from_page(pdf_path, toc_page_numbers):
    doc = fitz.open(pdf_path)
    toc_items = []
    
    for page_num in toc_page_numbers:
        # PyMuPDF页码从0开始,需减1
        page = doc.load_page(page_num - 1)
        # 获取带格式的文本块信息
        blocks = page.get_text("dict")["blocks"]
        
        for block in blocks:
            if "lines" not in block:
                continue
            for line in block["lines"]:
                # 提取该行的核心特征
                font_size = line["spans"][0]["size"]
                left_offset = line["bbox"][0]
                text = "".join([span["text"].strip() for span in line["spans"]])
                if not text:
                    continue
                
                # 根据实际PDF格式调整层级判断阈值
                if font_size >= 14:
                    level = 1
                elif font_size >= 12 and left_offset > 20:
                    level = 2
                elif font_size >= 10 and left_offset > 40:
                    level = 3
                else:
                    continue  # 跳过非目录文本
                
                toc_items.append((level, text))
    
    doc.close()
    
    # 格式化输出
    formatted_toc = []
    for level, title in toc_items:
        indent = "    " * (level - 1)
        formatted_toc.append(f"{indent}{level}. {title}")
    
    return "\n".join(formatted_toc)

# 使用示例:假设目录在第3、4页
pdf_path = "your_book.pdf"
print(extract_toc_from_page(pdf_path, [3,4]))

说明:

  • 通过get_text("dict")获取文本的字体大小、位置坐标等元数据,是区分层级的关键。
  • 需根据目标PDF的实际排版调整字体大小和缩进的阈值(比如有的一级标题用16号字,子标题缩进30px等)。
  • 可额外添加正则匹配逻辑,提取标题后的页码信息,完善目录内容。

补充说明

  • 之前用PyPDF2/PyMuPDF失败,大概率是只提取了纯文本,没利用内置书签或文本格式特征。
  • 如果是扫描版PDF(图片格式),需先用pytesseract做OCR识别,再用上述方法处理。

内容的提问来源于stack exchange,提问作者Mido Gimo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 01:51:26