Python PDF提取目录书签 大纲导出教程
用Python读取PDF内置书签/大纲(Outlines),提取章节名和对应页码,导出为Excel或TXT,方便做索引目录。
场景痛点
很多PDF(尤其是电子书、合同、规范)自带左侧书签目录,但想把这份目录导出到Excel里做索引、转成Markdown目录、或者给飞书文档当锚点,手动一条条复制太慢。用Python直接读取PDF的Outlines对象,把章节名+页码一次性导出成表格,几秒钟搞定。
用到的库
pip install PyPDF2
完整代码
# -*- coding: utf-8 -*-
"""
提取 PDF 的书签(大纲)结构,导出为 txt / Excel
"""
from PyPDF2 import PdfReader
import pandas as pd
def _walk_outlines(outlines, reader, level=1, result=None):
"""
递归遍历书签树,把层级、标题、页码拍平成一行一条
"""
if result is None:
result = []
for item in outlines:
# 子书签是嵌套列表
if isinstance(item, list):
_walk_outlines(item, reader, level + 1, result)
else:
# item 是 Destination 对象,title 是标题,page 是页面对象
title = item.title
try:
# get_destination_page_number 返回 0 基页码
page_no = reader.get_destination_page_number(item) + 1
except Exception:
page_no = None
result.append({"层级": level, "标题": title, "页码": page_no})
return result
def extract_bookmarks(pdf_path: str, out_excel: str = None) -> list:
"""
提取 PDF 书签
"""
reader = PdfReader(pdf_path)
# outlines 是书签树根节点,可能是嵌套列表
outlines = reader.outline
rows = _walk_outlines(outlines, reader)
print(f"共提取 {len(rows)} 个书签")
for row in rows:
indent = " " * (row["层级"] - 1)
print(f"{indent}[P{row['页码']}] {row['标题']}")
if out_excel:
df = pd.DataFrame(rows)
df.to_excel(out_excel, index=False)
print(f"已导出 Excel: {out_excel}")
return rows
if __name__ == "__main__":
extract_bookmarks("with_toc.pdf", "bookmarks.xlsx")
代码讲解
reader.outline是PDF的大纲树根节点,结构是嵌套列表:一级书签是 Destination 对象,其下的二级书签是一个子列表。_walk_outlines递归遍历:遇到 list 就加深一层继续递归,遇到 Destination 就记录一行。reader.get_destination_page_number(item)返回该书签跳到的0基页码,+1 转成人类习惯的 1 基页码。- 最后用 pandas 导出 Excel,三列:层级、标题、页码,方便按层级缩进查看。
- 控制台打印时用空格缩进体现层级关系,直接就能看到目录树。
运行结果
控制台按层级打印书签树,如:
[P1] 封面
[P3] 第一章 项目背景
[P3] 1.1 行业现状
[P5] 1.2 市场规模
同目录生成 bookmarks.xlsx,三列结构清晰。
注意事项
- 不是所有PDF都有书签,没有书签的
reader.outline是空列表。 - 有些书签指向命名目标(named destination),
get_destination_page_number可能返回异常,脚本已 try/except 兜底为 None。 - 层级深度取决于原PDF怎么做的书签,脚本会原样保留。
- 想按书签拆分整本PDF。

更新时间:2026-09-14 21:39:33