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

PDF目录提取异常:仅1/50文档可提取,求排查与解决方案

PDF目录提取失败的原因与解决方案

核心原因分析

  • PDF无内置书签(TOC):你使用doc.get_toc()提取的是PDF的官方内置书签,但多数PDF的目录只是页面上的静态文本/链接(视觉上的目录栏),并没有被标记为PDF标准的书签结构,因此get_toc()返回空列表。这是最常见的失效原因。
  • 代码存储逻辑缺陷:你的代码用page作为字典key存储书签,若同一页存在多个书签,后面的条目会直接覆盖前面的,导致信息丢失(即使提取到书签也会不全)。
  • 特殊PDF格式限制:少数PDF可能存在加密、损坏情况;若目录是图片形式(扫描件),get_toc()也无法读取——但你提到目录清晰可识别,扫描件概率较低。加密PDF会直接导致get_toc()无法访问内容,需先解密。

解决方案

1. 兼容内置书签与页面文本目录

针对无内置书签的PDF,需要提取页面文本并解析目录结构,以下是改进后的代码:

from typing import List
import os
import fitz
import re

def get_bookmarks(filepath: str) -> List[List[int, str, int]]:
    """提取PDF目录,优先内置书签,无则尝试解析前3页文本目录"""
    with fitz.open(filepath) as doc:
        # 尝试解密(空密码适用于无密码加密的PDF,有密码需传入对应值)
        if doc.is_encrypted:
            doc.authenticate("")
        
        # 先提取内置书签
        toc = doc.get_toc()
        if toc:
            return toc
        
        # 无内置书签,解析前3页的文本目录
        toc = []
        for page_num in range(min(3, doc.page_count)):
            page = doc.load_page(page_num)
            text = page.get_text("text")
            lines = text.split("\n")
            
            # 正则匹配目录行:标题 + 末尾页码(兼容点、空格等分隔符)
            pattern = re.compile(r'^\s*(.*?)\s+([\d]+)\s*$')
            for line in lines:
                match = pattern.match(line)
                if match:
                    title = match.group(1).strip()
                    target_page = int(match.group(2))
                    # 默认层级为1,可根据行首空格数判断子层级(可选)
                    toc.append([1, title, target_page])
        return toc

def export_toc(filepath: str, toc: List[List[int, str, int]]):
    """将提取的目录导出为文本文件"""
    if not toc:
        return
    output_path = os.path.splitext(filepath)[0] + "_toc.txt"
    with open(output_path, "w", encoding="utf-8") as f:
        for level, title, page in toc:
            indent = "  " * (level - 1)
            f.write(f"{indent}{title} —— 第{page}页\n")

# 批量处理目录
for root, _, files in os.walk("doc/"):
    for file in files:
        if not file.lower().endswith(".pdf"):
            continue
        file_path = os.path.join(root, file)
        toc = get_bookmarks(file_path)
        print(f"文件:{file_path} | 目录条目数:{len(toc)}")
        export_toc(file_path, toc)

2. 优化书签存储逻辑

放弃用page作为字典key,改用原始的列表格式存储所有书签,避免同一页多书签的覆盖问题。

3. 处理加密PDF

若PDF有密码,需在doc.authenticate()中传入正确密码;若不知道密码,无法提取任何内容。

进阶优化(可选)

  • 若目录有层级(如缩进的子标题),可通过统计行首空格/制表符数量,进一步判断目录层级,完善正则或解析逻辑。
  • 若PDF目录是图片格式(扫描件),需结合OCR工具(如pytesseract)提取文本后再解析。

内容的提问来源于stack exchange,提问作者Lorenzo Cutrupi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:38:21