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 技术批量提取不可编辑的文档内容!

相关推荐
2401_8346369912 分钟前
Docker 容器化技术全解:从镜像构建到容器编排的完整教案1
java·docker·容器
青 春 记 忆13 分钟前
零基础入门python31:Django商城第一步——创建项目并跑通第一个请求
python·django·后端开发
孫治AllenSun13 分钟前
【LangChain4J-06】Prompt 工程与模板化开发
开发语言·python·prompt
qq_4260039614 分钟前
多语言新增语种全量测试策略
前端·javascript·python·pycharm·自动化
AuLuo-17 分钟前
SearXNG 物理机部署搭建免费搜索引擎服务
python·搜索引擎
jjjava2.018 分钟前
初步认识接口测试
java·可用性测试
吠品20 分钟前
TortoiseSVN 状态图标不显示的排查与解决办法
java·服务器·数据库
wuyk55521 分钟前
9.冒泡排序:像鱼缸泡泡一样的简单排序算法
开发语言·stm32·单片机·算法·排序算法