Python办公17:暴力拆分——按页数或指定范围提取 PDF 核心页面

17:PDF 暴力拆分------按页数或指定范围提取 PDF 核心页面

第三阶段:PDF 与图片处理(16-22)

场景引入

收到一份 200 页的培训教材,但你只需要第 15-30 页的内容。或者需要把一份合同的每个章节拆分为独立文件,分发给不同负责人。

手动操作需要打开 PDF,选择页面范围,导出------每次只能处理一部分。本节教你用 Python 快速拆分和提取。


技术原理

核心操作:

复制代码
源 PDF → 按页拆分 → 按范围提取 → 多个独立 PDF

使用 pypdfPdfReader 读取页面,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 技术批量提取不可编辑的文档内容!

相关推荐
阿洛学长6 分钟前
计算机二级 Python 基本操作题(15 分)真题笔记(0101 ~ 1903 全套)
python·pycharm
君顾19 分钟前
上海24小时自助健身房系统开发实战指南:从架构设计到落地部署
java·开发语言·健身房
weixin1997010801632 分钟前
[特殊字符]️《二手ERP对接电商平台的总体方案:统一数据模型 + 事件驱动 + 灰度上线6原则》(附Python源码)
大数据·python
香菜TTT1 小时前
大模型上下文协议(MCP):AI 应用的“USB-C”接口技术
开发语言·人工智能·经验分享
aramae1 小时前
模拟实现strlen()函数 (C语言)
c语言·开发语言·后端
滚雪球~1 小时前
量化交易 防止Windows电脑自动更新并重启
python·量化
SL_staff1 小时前
别急着买商业规则引擎:90%风控场景根本不需要全量编码能力
java·程序员·groovy
ManageEngineITSM2 小时前
DevOps和ITIL是什么关系?是替代还是互补一文讲清
java·服务器·资产管理·变更管理
jimy12 小时前
readelf 查看“派生类”的vtable符号
开发语言·c++
L@ncor2 小时前
第二章可能出现的问题
人工智能·python