17:PDF 暴力拆分------按页数或指定范围提取 PDF 核心页面
第三阶段:PDF 与图片处理(16-22)
场景引入
收到一份 200 页的培训教材,但你只需要第 15-30 页的内容。或者需要把一份合同的每个章节拆分为独立文件,分发给不同负责人。
手动操作需要打开 PDF,选择页面范围,导出------每次只能处理一部分。本节教你用 Python 快速拆分和提取。
技术原理
核心操作:
源 PDF → 按页拆分 → 按范围提取 → 多个独立 PDF
使用 pypdf 的 PdfReader 读取页面,PdfWriter 写入指定页面。
环境准备
bash
pip install pypdf
完整代码
python
import os
from pypdf import PdfReader, PdfWriter
from pathlib import Path
# ==================== 方案 1:提取指定页码范围 ====================
def extract_pages(input_pdf, start_page, end_page, output_file):
"""
从 PDF 中提取指定范围的页面
参数:
input_pdf: 源 PDF 文件
start_page: 起始页码(从 1 开始)
end_page: 结束页码(包含)
output_file: 输出文件名
"""
reader = PdfReader(input_pdf)
total = len(reader.pages)
# 验证页码范围
if start_page < 1 or end_page > total:
print(f"错误: 文件共 {total} 页,请求范围 {start_page}-{end_page}")
return
writer = PdfWriter()
for i in range(start_page - 1, end_page): # 转为 0-based 索引
writer.add_page(reader.pages[i])
with open(output_file, 'wb') as f:
writer.write(f)
print(f"已提取第 {start_page}-{end_page} 页 → {output_file}")
# ==================== 方案 2:逐页拆分 ====================
def split_pdf_by_page(input_pdf, output_dir="逐页拆分"):
"""
将 PDF 的每一页拆分为独立文件
"""
reader = PdfReader(input_pdf)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
base_name = Path(input_pdf).stem
for i, page in enumerate(reader.pages):
writer = PdfWriter()
writer.add_page(page)
output_file = output_path / f"{base_name}_第{i+1}页.pdf"
with open(output_file, 'wb') as f:
writer.write(f)
print(f"逐页拆分完成: {len(reader.pages)} 页 → {output_dir}/")
# ==================== 方案 3:按指定块大小拆分 ====================
def split_pdf_by_chunks(input_pdf, chunk_size, output_dir="分块拆分"):
"""
按指定页数拆分(如每 10 页一个文件)
参数:
input_pdf: 源 PDF
chunk_size: 每个文件的页数
output_dir: 输出目录
"""
reader = PdfReader(input_pdf)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
total = len(reader.pages)
base_name = Path(input_pdf).stem
chunk_count = 0
for start in range(0, total, chunk_size):
end = min(start + chunk_size, total)
writer = PdfWriter()
for i in range(start, end):
writer.add_page(reader.pages[i])
output_file = output_path / f"{base_name}_第{start+1}-{end}页.pdf"
with open(output_file, 'wb') as f:
writer.write(f)
chunk_count += 1
print(f"已拆分: 第 {start+1}-{end} 页")
print(f"\n分块拆分完成: {chunk_count} 个文件")
# ==================== 方案 4:按章节/书签拆分 ====================
def split_pdf_by_outline(input_pdf, output_dir="按章节拆分"):
"""
按 PDF 的书签(大纲)拆分为独立章节文件
"""
reader = PdfReader(input_pdf)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
base_name = Path(input_pdf).stem
outline = reader.outline
# 提取书签信息
bookmarks = []
for item in outline:
if isinstance(item, dict) and '/Title' in item:
title = item['/Title']
page_num = None
if '/Dest' in item:
dest = item['/Dest']
if isinstance(dest, list) and dest[0]:
page_num = reader.get_destination_page_number(item)
bookmarks.append({'title': title, 'page': page_num})
if not bookmarks:
print("该 PDF 没有书签/大纲")
return
# 按书签拆分
for idx, bm in enumerate(bookmarks):
if bm['page'] is None:
continue
start = bm['page']
# 下一个书签的页码 - 1 作为结束
if idx + 1 < len(bookmarks) and bookmarks[idx + 1]['page'] is not None:
end = bookmarks[idx + 1]['page'] - 1
else:
end = len(reader.pages) - 1
writer = PdfWriter()
for i in range(start, end + 1):
writer.add_page(reader.pages[i])
safe_title = bm['title'].replace('/', '_').replace('\\', '_')
output_file = output_path / f"{safe_title}.pdf"
with open(output_file, 'wb') as f:
writer.write(f)
print(f"已拆分章节: {bm['title']} (第 {start+1}-{end+1} 页)")
print(f"\n按章节拆分完成: {output_dir}/")
# ==================== 使用示例 ====================
if __name__ == "__main__":
PDF_FILE = "培训教材_200页.pdf"
# 方案 1:提取第 15-30 页
extract_pages(PDF_FILE, 15, 30, "培训教材_核心章节.pdf")
# 方案 2:逐页拆分
# split_pdf_by_page(PDF_FILE)
# 方案 3:每 10 页一个文件
# split_pdf_by_chunks(PDF_FILE, chunk_size=10)
# 方案 4:按书签拆分
# split_pdf_by_outline(PDF_FILE)
常见问题
Q1:提取后页面空白?
pypdf 可能无法正确处理某些特殊 PDF(如扫描件、加密文件)。尝试先解密:
python
if reader.is_encrypted:
reader.decrypt("")
Q2:按书签拆分时没有提取到书签?
有些 PDF 的书签存储在非标准位置。可以使用 pdfplumber 获取更多信息:
python
import pdfplumber
with pdfplumber.open(pdf_file) as pdf:
toc = pdf.toc
print(toc)
总结
| 拆分方式 | 函数 | 说明 |
|---|---|---|
| 指定范围 | extract_pages() |
提取 start-end 页 |
| 逐页拆分 | split_pdf_by_page() |
每页一个文件 |
| 分块拆分 | split_pdf_by_chunks() |
每 N 页一个文件 |
| 按书签 | split_pdf_by_outline() |
按章节拆分 |
本节掌握了 PDF 拆分与页面提取的多种方法。
下一节预告:18:PDF 转 Word------利用 OCR 技术批量提取不可编辑的文档内容!