导航菜单

  • 1.vector
  • 2.milvus
  • 3.pymilvus
  • 4.rag
  • 5.rag_measure
  • 7.search
  • ragflow
  • heapq
  • HNSW
  • cosine_similarity
  • math
  • typing
  • etcd
  • minio
  • collections
  • jieba
  • random
  • beautifulsoup4
  • chromadb
  • sentence_transformers
  • numpy
  • lxml
  • openpyxl
  • PyMuPDF
  • python-docx
  • requests
  • python-pptx
  • text_splitter
  • all-MiniLM-L6-v2
  • openai
  • llm
  • BPETokenizer
  • Flask
  • RAGAS
  • BagofWords
  • langchain
  • Pydantic
  • abc
  • faiss
  • MMR
  • scikit-learn
  • 1. 什么是 PyMuPDF?
  • 2. 环境准备
    • 2.1 检查 Python 版本
    • 2.2 安装 PyMuPDF
    • 2.3 验证安装
  • 3. 核心概念
    • 3.1 Document(文档对象)
    • 3.2 Page(页面对象)
    • 3.3 Rect(矩形对象)
    • 3.4 坐标系统
  • 4. 快速体验:打开和读取 PDF
    • 4.1 打开 PDF 文档
  • 5. 文本提取:从 PDF 中提取文本
    • 5.1 提取完整文本
    • 5.2 提取文本块
    • 5.3 提取单词级别的信息
  • 6. 图片提取:从 PDF 中提取图片
    • 6.1 提取并保存图片
  • 7. 创建和编辑 PDF:创建新文档和修改现有文档
    • 7.1 创建新 PDF 并添加文本
    • 7.2 修改现有 PDF(添加文本和绘制)
  • 8. 合并和拆分 PDF:批量处理 PDF 文件
    • 8.1 合并多个 PDF 文件
    • 8.2 拆分 PDF 文件
  • 9. PDF 转图片:将 PDF 页面转换为图片
    • 9.1 PDF 页面转图片
  • 10. 搜索和高亮:在 PDF 中搜索文本并添加高亮
    • 10.1 搜索文本并添加高亮
    • 10.2 添加文本注释
  • 11. 实战案例:PDF 处理工具
  • 12. 常见问题与排查
    • 12.1 文件不存在错误
    • 12.2 内存管理问题
    • 12.3 中文显示问题
  • 13. 参考

1. 什么是 PyMuPDF? #

PyMuPDF 是 Python 中最强大的 PDF 处理库之一,它是 MuPDF 引擎的 Python 绑定。虽然导入时使用 fitz(这是历史原因),但库名是 PyMuPDF。它可以处理 PDF、XPS、EPUB 等多种格式,功能强大且性能优秀。

为什么要用 PyMuPDF?

想象一下,你需要从 PDF 中提取文本、提取图片、合并多个 PDF 文件,或者创建新的 PDF 文档。手动操作太慢且容易出错,而 PyMuPDF 提供了强大的 Python API,可以自动化完成这些任务。

PyMuPDF 的优势:

  • 功能强大:支持文本提取、图片提取、PDF 创建、页面编辑等多种操作
  • 性能优秀:基于 C 语言实现,处理速度快
  • 精确度高:可以精确提取文本位置、图片坐标等信息
  • 易于使用:API 设计简洁直观,文档完善
  • 跨平台:Windows、macOS、Linux 都可以使用

前置知识补充:

  • PDF(可移植文档格式):PDF 是一种用于展示文档的文件格式,可以包含文本、图片、表格等多种内容。PDF 文件可以在不同设备和系统上保持一致的显示效果。
  • 页面(Page):PDF 文档由多个页面组成,每个页面是独立的,类似于书籍中的一页。
  • 坐标系统:PDF 使用坐标系统来定位元素。通常以页面左下角为原点 (0, 0),X 轴向右,Y 轴向上。
  • 元数据(Metadata):PDF 文件可以包含元数据信息,如标题、作者、创建日期等。

为什么导入名是 fitz?:这是历史原因。PyMuPDF 的开发者最初使用 fitz 作为导入名,这个名称来源于 MuPDF 的一个渲染引擎。虽然库名是 PyMuPDF,但导入时仍然使用 import fitz。

2. 环境准备 #

在学习 PyMuPDF 之前,需要确保你的 Python 环境已经准备好。PyMuPDF 支持 Python 3.7 及以上版本。

2.1 检查 Python 版本 #

在安装之前,先检查一下你的 Python 版本是否符合要求。

# Windows PowerShell:查看 Python 版本
python --version
# macOS 终端:查看 Python 版本
python3 --version

2.2 安装 PyMuPDF #

PyMuPDF 可以直接通过 pip 安装。安装过程会自动下载所需的依赖包。

# 说明:Windows PowerShell 安装 PyMuPDF
# 先升级 pip 到最新版本,确保能正常安装依赖
python -m pip install --upgrade pip
# 安装 PyMuPDF 库
python -m pip install PyMuPDF
# 说明:macOS / Linux 终端安装 PyMuPDF
# 先升级 pip 到最新版本
python3 -m pip install --upgrade pip
# 安装 PyMuPDF 库
python3 -m pip install PyMuPDF

网络加速提示:如果从 PyPI 下载较慢,可以使用国内镜像:

  • Windows: python -m pip install PyMuPDF -i https://pypi.tuna.tsinghua.edu.cn/simple
  • macOS: python3 -m pip install PyMuPDF -i https://pypi.tuna.tsinghua.edu.cn/simple

安装问题提示:

  • 如果安装失败,可能是因为网络问题。可以尝试使用镜像源,或者检查网络连接。
  • macOS 用户如果遇到权限问题,可以在命令前加 sudo(不推荐),或者使用虚拟环境。
  • 如果遇到编译错误,可能需要安装系统依赖。大多数情况下,pip 会自动处理这些依赖。

2.3 验证安装 #

安装完成后,验证一下是否安装成功。

# -*- coding: utf-8 -*-
# 说明:验证 PyMuPDF 是否安装成功

# 说明:导入 fitz 模块(PyMuPDF 的导入名)
# 虽然库名是 PyMuPDF,但导入时使用 fitz
import fitz

# 说明:打印 PyMuPDF 版本信息
# version 属性返回库的版本号
print(f"PyMuPDF 版本:{fitz.version}")

# 说明:测试创建一个空的 PDF 文档
# fitz.open() 不传参数时创建一个新的空文档
doc = fitz.open()

# 说明:创建一个新页面
# new_page() 方法在文档末尾添加一个新页面
# 参数可以指定页面大小,不传参使用默认大小(A4)
page = doc.new_page()

# 说明:在页面上插入文本
# insert_text() 方法在指定位置插入文本
# 参数:(x, y) 坐标,文本内容,字体大小
page.insert_text((72, 72), "Hello PyMuPDF!", fontsize=16)

# 说明:保存文档到文件
# save() 方法将文档保存到指定的文件路径
doc.save("test.pdf")

# 说明:关闭文档
# close() 方法关闭文档,释放资源
doc.close()

# 说明:打印结果,验证安装是否成功
print("安装成功!已创建测试文件:test.pdf")

# 说明:如果没有报错并创建了 test.pdf 文件,说明安装成功

3. 核心概念 #

在使用 PyMuPDF 之前,需要理解几个核心概念。这些概念是理解 PyMuPDF 的基础。

3.1 Document(文档对象) #

Document 是 PDF 文档的对象表示,相当于整个 PDF 文件。你可以通过 fitz.open() 打开已有的 PDF 文件,或创建新的 PDF 文档。

3.2 Page(页面对象) #

Page 是 PDF 文档中的一个页面,类似于书籍中的一页。每个 Page 对象可以独立操作,如提取文本、插入内容等。

3.3 Rect(矩形对象) #

Rect 用于表示页面上的一个矩形区域,用于定位和裁剪。它由四个值组成:左、上、右、下坐标。

3.4 坐标系统 #

PyMuPDF 使用 PDF 的坐标系统:以页面左下角为原点 (0, 0),X 轴向右,Y 轴向上。这与常见的图像坐标系统(左上角为原点)不同。

4. 快速体验:打开和读取 PDF #

让我们通过一个最简单的例子来快速体验 PyMuPDF 的强大功能。

4.1 打开 PDF 文档 #

方法/属性 功能说明 常用参数 返回值
fitz.open() 打开 PDF 文档 filename:文件路径(可选,不传参创建新文档) Document 对象
.page_count 获取文档的页数 无(属性) 整数
.metadata 获取文档的元数据 无(属性) 字典
doc[index] 通过索引访问页面 index:页面索引(从 0 开始) Page 对象
.rect 获取页面的矩形区域 无(属性) Rect 对象
.close() 关闭文档 无 无
# -*- coding: utf-8 -*-
# 说明:快速体验 PyMuPDF - 打开和读取 PDF 文档

# 说明:导入 fitz 模块
# 虽然库名是 PyMuPDF,但导入时使用 fitz
import fitz

# 说明:打开一个 PDF 文档
# fitz.open() 函数打开指定的 PDF 文件
# 返回 Document 对象
doc = fitz.open("example.pdf")

# 说明:获取文档的页数
# page_count 属性返回文档的总页数
page_count = doc.page_count
print(f"PDF 文档总页数:{page_count}")

# 说明:获取文档的元数据
# metadata 属性返回文档的元数据字典
# 包含标题、作者、创建日期等信息
metadata = doc.metadata
print("\n文档元数据:")
for key, value in metadata.items():
    print(f"  {key}:{value}")

# 说明:遍历每一页并获取页面信息
# 可以通过索引访问页面(从 0 开始)
print("\n页面信息:")
for page_number in range(doc.page_count):
    # 说明:通过索引获取页面对象
    # doc[0] 表示第一页,doc[1] 表示第二页
    page = doc[page_number]

    # 说明:获取页面的矩形区域
    # rect 属性返回页面的矩形区域(包含宽度和高度)
    rect = page.rect
    print(f"  第 {page_number + 1} 页:")
    print(f"    宽度:{rect.width:.2f} 点")
    print(f"    高度:{rect.height:.2f} 点")

# 说明:使用完毕后关闭文档
# close() 方法关闭文档,释放资源
# 这是一个好习惯,可以避免内存泄漏
doc.close()

print("\n文档已关闭")

注意:上面的代码需要当前目录中存在 example.pdf 文件。如果没有这个文件,代码会报错。在实际使用中,请替换为你自己的 PDF 文件路径。

5. 文本提取:从 PDF 中提取文本 #

PyMuPDF 可以精确提取 PDF 中的文本,包括完整文本、文本块和单词级别的信息。本节介绍如何提取文本。

5.1 提取完整文本 #

方法 功能说明 常用参数 返回值
.get_text() 提取页面的文本内容 textpage:是否使用 TextPage 对象(可选) 字符串
# -*- coding: utf-8 -*-
# 说明:演示如何提取 PDF 页面的完整文本

# 说明:导入 fitz 模块
import fitz

# 说明:打开 PDF 文档
doc = fitz.open("example.pdf")

# 说明:获取第一页
# 使用索引 0 访问第一页
page = doc[0]

# 说明:提取页面的完整文本
# get_text() 方法提取页面上的所有文本
# 返回一个字符串,包含页面上的所有文本内容
text = page.get_text()

# 说明:打印提取的文本
print("第一页的文本内容:")
print(text)

# 说明:提取所有页面的文本
print("\n所有页面的文本:")
for page_number in range(doc.page_count):
    # 说明:获取每一页
    page = doc[page_number]

    # 说明:提取该页的文本
    text = page.get_text()

    # 说明:打印页号和文本(只显示前 100 个字符)
    print(f"\n第 {page_number + 1} 页(前 100 个字符):")
    print(text[:100] if text else "(无文本内容)")

# 说明:关闭文档
doc.close()

5.2 提取文本块 #

方法 功能说明 常用参数 返回值
.get_text() 提取页面的文本,支持多种格式 format:文本格式("text"、"blocks"、"words"、"dict" 等) 列表或字符串
# -*- coding: utf-8 -*-
# 说明:演示如何提取文本块(包含位置信息)

# 说明:导入 fitz 模块
import fitz

# 说明:打开 PDF 文档
doc = fitz.open("example.pdf")

# 说明:获取第一页
page = doc[0]

# 说明:提取文本块
# get_text("blocks") 返回文本块列表
# 每个文本块是一个元组:(x0, y0, x1, y1, "文本内容", 块号, 类型)
# x0, y0, x1, y1 是文本块的坐标(矩形区域)
blocks = page.get_text("blocks")

# 说明:遍历文本块并打印信息
print("文本块信息:")
for idx, block in enumerate(blocks):
    # 说明:block 是一个元组,包含文本块的信息
    # block[:4] 是坐标(x0, y0, x1, y1)
    # block[4] 是文本内容
    x0, y0, x1, y1 = block[:4]
    text_content = block[4]

    print(f"\n文本块 {idx + 1}:")
    print(f"  坐标:({x0:.2f}, {y0:.2f}) 到 ({x1:.2f}, {y1:.2f})")
    print(f"  内容:{text_content[:50]}...")  # 只显示前 50 个字符

# 说明:关闭文档
doc.close()

5.3 提取单词级别的信息 #

方法 功能说明 常用参数 返回值
.get_text("words") 提取单词级别的信息 无 列表,每个元素是 (x0, y0, x1, y1, "单词", 块号, 行号, 词号)
# -*- coding: utf-8 -*-
# 说明:演示如何提取单词级别的信息(包含位置)

# 说明:导入 fitz 模块
import fitz

# 说明:打开 PDF 文档
doc = fitz.open("example.pdf")

# 说明:获取第一页
page = doc[0]

# 说明:提取单词级别的信息
# get_text("words") 返回单词列表
# 每个单词是一个元组:(x0, y0, x1, y1, "单词", 块号, 行号, 词号)
# x0, y0, x1, y1 是单词的坐标
words = page.get_text("words")

# 说明:打印前 10 个单词的信息
print("前 10 个单词的信息:")
for idx, word in enumerate(words[:10]):
    # 说明:word 是一个元组,包含单词的信息
    # word[:4] 是坐标(x0, y0, x1, y1)
    # word[4] 是单词内容
    x0, y0, x1, y1 = word[:4]
    word_text = word[4]

    print(f"\n单词 {idx + 1}:{word_text}")
    print(f"  坐标:({x0:.2f}, {y0:.2f}) 到 ({x1:.2f}, {y1:.2f})")

# 说明:统计单词数量
print(f"\n总共找到 {len(words)} 个单词")

# 说明:关闭文档
doc.close()

6. 图片提取:从 PDF 中提取图片 #

PyMuPDF 可以提取 PDF 中嵌入的图片,并保存为 PNG 或 JPG 格式。本节介绍如何提取图片。

6.1 提取并保存图片 #

方法/属性 功能说明 常用参数 返回值
.get_images() 获取页面上的所有图片 无 列表,每个元素是 (xref, smask, width, height, bpc, colorspace, alt.colorspace, name, filter, referencer)
fitz.Pixmap() 创建图片对象 doc:文档对象,xref:图片的交叉引用编号 Pixmap 对象
.n 获取颜色通道数 无(属性) 整数
.alpha 是否有透明通道 无(属性) 整数(0 或 1)
.save() 保存图片到文件 filename:文件路径 无
# -*- coding: utf-8 -*-
# 说明:演示如何从 PDF 中提取图片

# 说明:导入 fitz 模块和 os 模块(用于文件操作)
import fitz
import os

# 说明:打开 PDF 文档
doc = fitz.open("example.pdf")

# 说明:获取第一页
page = doc[0]

# 说明:获取页面上的所有图片
# get_images() 方法返回页面上的所有图片信息
# 返回一个列表,每个元素包含图片的元数据
images = page.get_images()

# 说明:打印图片数量
print(f"第一页找到 {len(images)} 张图片")

# 说明:遍历所有图片并保存
for index, img in enumerate(images):
    # 说明:img 是一个元组,包含图片的信息
    # img[0] 是图片的交叉引用编号(xref),用于获取图片数据
    xref = img[0]

    # 说明:使用 Pixmap 对象提取图片
    # Pixmap(doc, xref) 从文档中提取指定编号的图片
    # 返回一个 Pixmap 对象,包含图片的像素数据
    pix = fitz.Pixmap(doc, xref)

    # 说明:检查图片格式
    # pix.n 是颜色通道数(3=RGB, 4=RGBA, 1=灰度)
    # pix.alpha 是透明通道标志(0=无透明,1=有透明)
    # pix.n - pix.alpha < 4 表示是标准格式(RGB 或灰度),可以直接保存
    if pix.n - pix.alpha < 4:
        # 说明:保存图片为 PNG 格式
        # save() 方法将图片保存到文件
        # 文件名包含页号和图片索引
        output_path = f"page0_img{index}.png"
        pix.save(output_path)
        print(f"  图片 {index + 1} 已保存:{output_path}")
    else:
        # 说明:如果图片格式特殊(如 CMYK),需要转换为 RGB
        # 创建一个新的 RGB 图片
        pix_rgb = fitz.Pixmap(fitz.csRGB, pix)
        output_path = f"page0_img{index}.png"
        pix_rgb.save(output_path)
        print(f"  图片 {index + 1} 已保存(已转换):{output_path}")
        # 说明:释放转换后的图片对象
        pix_rgb = None

    # 说明:释放图片对象,释放内存
    # 这是重要的步骤,可以避免内存泄漏
    pix = None

# 说明:提取所有页面的图片
print("\n提取所有页面的图片:")
for page_number in range(doc.page_count):
    page = doc[page_number]
    images = page.get_images()

    for img_index, img in enumerate(images):
        xref = img[0]
        pix = fitz.Pixmap(doc, xref)

        if pix.n - pix.alpha < 4:
            output_path = f"page{page_number}_img{img_index}.png"
            pix.save(output_path)
            print(f"  第 {page_number + 1} 页,图片 {img_index + 1}:{output_path}")

        pix = None

# 说明:关闭文档
doc.close()
print("\n图片提取完成")

7. 创建和编辑 PDF:创建新文档和修改现有文档 #

PyMuPDF 不仅可以读取 PDF,还可以创建新的 PDF 文档和修改现有文档。本节介绍如何创建和编辑 PDF。

7.1 创建新 PDF 并添加文本 #

方法 功能说明 常用参数 返回值
fitz.open() 创建新的空文档 无 Document 对象
.new_page() 在文档末尾添加新页面 width、height:页面大小(可选) Page 对象
.insert_text() 在页面上插入文本 point:坐标 (x, y),text:文本内容,fontsize:字体大小(可选),color:颜色(可选) 无
.save() 保存文档到文件 filename:文件路径 无
.close() 关闭文档 无 无
# -*- coding: utf-8 -*-
# 说明:演示如何创建新的 PDF 文档并添加文本

# 说明:导入 fitz 模块
import fitz

# 说明:创建一个新的空 PDF 文档
# fitz.open() 不传参数时创建一个新的空文档
doc = fitz.open()

# 说明:在文档中添加一个新页面
# new_page() 方法在文档末尾添加一个新页面
# 不传参数时使用默认大小(A4,约 595 x 842 点)
page = doc.new_page()

# 说明:在页面上插入文本
# insert_text() 方法在指定位置插入文本
# 参数:(x, y) 坐标,文本内容,字体大小(可选)
# 坐标单位是点(point),72 点 = 1 英寸
# (72, 72) 表示距离左边缘和底边缘各 1 英寸的位置
page.insert_text((72, 72), "Hello PyMuPDF!", fontsize=16)

# 说明:插入更多文本(中文)
# 可以多次调用 insert_text() 添加多个文本
page.insert_text((72, 100), "欢迎使用 PyMuPDF!", fontsize=14)

# 说明:插入带颜色的文本
# color 参数设置文本颜色,格式为 (r, g, b),值范围 0-1
# (1, 0, 0) 表示红色
page.insert_text((72, 128), "这是红色文本", fontsize=12, color=(1, 0, 0))

# 说明:添加多个页面
for i in range(2, 4):
    # 说明:创建新页面
    new_page = doc.new_page()
    # 说明:在新页面上添加内容
    new_page.insert_text((72, 72), f"这是第 {i} 页", fontsize=16)

# 说明:保存文档到文件
# save() 方法将文档保存到指定的文件路径
# 如果文件已存在,会被覆盖
doc.save("hello.pdf")

# 说明:关闭文档
# close() 方法关闭文档,释放资源
doc.close()

print("PDF 文档已创建:hello.pdf")
print("文档包含 3 页,每页都有文本内容")

7.2 修改现有 PDF(添加文本和绘制) #

方法 功能说明 常用参数 返回值
.draw_rect() 在页面上绘制矩形 rect:矩形区域,color:填充颜色(可选),width:边框宽度(可选),fill:是否填充(可选) 无
.draw_line() 在页面上绘制直线 p1:起点坐标,p2:终点坐标,color:线条颜色(可选),width:线条宽度(可选) 无
fitz.Rect() 创建矩形对象 x0, y0, x1, y1:矩形的四个坐标 Rect 对象
# -*- coding: utf-8 -*-
# 说明:演示如何修改现有 PDF(添加文本和绘制图形)

# 说明:导入 fitz 模块
import fitz

# 说明:打开现有的 PDF 文档
doc = fitz.open("example.pdf")

# 说明:获取第一页
page = doc[0]

# 说明:在页面上插入文本(添加到现有内容上)
page.insert_text((100, 100), "这是添加的文本", fontsize=12, color=(0, 0, 1))

# 说明:绘制一个矩形
# fitz.Rect(x0, y0, x1, y1) 创建一个矩形对象
# x0, y0 是左下角坐标,x1, y1 是右上角坐标
rect = fitz.Rect(50, 50, 200, 150)

# 说明:draw_rect() 方法绘制矩形
# color 参数设置颜色,(1, 0, 0) 表示红色
# fill 参数设置为 True 表示填充矩形
# width 参数设置边框宽度
page.draw_rect(rect, color=(1, 0, 0), fill=True, width=2)

# 说明:绘制一条直线
# draw_line() 方法绘制直线
# p1 是起点坐标,p2 是终点坐标
# color 参数设置线条颜色,(0, 1, 0) 表示绿色
# width 参数设置线条宽度
page.draw_line((100, 200), (300, 300), color=(0, 1, 0), width=3)

# 说明:插入带背景色的文本(通过绘制矩形实现)
text_rect = fitz.Rect(250, 250, 400, 280)
page.draw_rect(text_rect, color=(1, 1, 0), fill=True)  # 黄色背景
page.insert_text((260, 260), "带背景的文本", fontsize=10, color=(0, 0, 0))

# 说明:保存修改后的文档
# 保存为新文件,避免覆盖原文件
doc.save("modified.pdf")

# 说明:关闭文档
doc.close()

print("修改后的 PDF 已保存:modified.pdf")

8. 合并和拆分 PDF:批量处理 PDF 文件 #

在实际应用中,你可能需要合并多个 PDF 文件或拆分一个大的 PDF 文件。本节介绍如何合并和拆分 PDF。

8.1 合并多个 PDF 文件 #

方法 功能说明 常用参数 返回值
.insert_pdf() 将另一个 PDF 的页面插入到当前文档 source:源文档对象,from_page:起始页(可选),to_page:结束页(可选),start_at:插入位置(可选) 无
# -*- coding: utf-8 -*-
# 说明:演示如何合并多个 PDF 文件

# 说明:导入 fitz 模块和 os 模块
import fitz
import os

# 说明:创建一个新的空 PDF 文档用于合并
# fitz.open() 不传参数时创建新文档
merged = fitz.open()

# 说明:要合并的 PDF 文件列表
pdf_files = ["doc1.pdf", "doc2.pdf", "doc3.pdf"]

# 说明:遍历每个 PDF 文件
for pdf_file in pdf_files:
    # 说明:检查文件是否存在
    if os.path.exists(pdf_file):
        # 说明:打开要合并的 PDF 文件
        source_doc = fitz.open(pdf_file)

        # 说明:将该 PDF 的所有页面插入到合并文档中
        # insert_pdf() 方法将源文档的页面插入到当前文档
        # 不指定 from_page 和 to_page 时,插入所有页面
        merged.insert_pdf(source_doc)

        # 说明:关闭源文档
        source_doc.close()

        print(f"已添加:{pdf_file}({source_doc.page_count} 页)")
    else:
        print(f"文件不存在:{pdf_file}")

# 说明:保存合并后的文档
merged.save("merged.pdf")

# 说明:关闭合并文档
merged.close()

print(f"\n合并完成!合并后的文档共 {merged.page_count} 页")
print("合并后的文件:merged.pdf")

注意:上面的代码需要当前目录中存在 doc1.pdf、doc2.pdf、doc3.pdf 文件。在实际使用中,请替换为你自己的 PDF 文件路径。

8.2 拆分 PDF 文件 #

方法 功能说明 常用参数 返回值
.insert_pdf() 将另一个 PDF 的页面插入到当前文档 source:源文档对象,from_page:起始页,to_page:结束页 无
# -*- coding: utf-8 -*-
# 说明:演示如何拆分 PDF 文件(按页拆分)

# 说明:导入 fitz 模块
import fitz

# 说明:打开要拆分的 PDF 文件
source = fitz.open("big.pdf")

# 说明:遍历每一页,将每一页保存为独立的 PDF
for page_number in range(source.page_count):
    # 说明:创建一个新的空文档
    target = fitz.open()

    # 说明:将源文档的当前页插入到新文档
    # insert_pdf() 方法的 from_page 和 to_page 参数指定页面范围
    # from_page=i, to_page=i 表示只插入第 i 页(从 0 开始)
    target.insert_pdf(source, from_page=page_number, to_page=page_number)

    # 说明:保存为单独的 PDF 文件
    # 文件名包含页码(从 1 开始)
    output_filename = f"page_{page_number + 1}.pdf"
    target.save(output_filename)

    # 说明:关闭新文档
    target.close()

    print(f"已保存:{output_filename}")

# 说明:关闭源文档
source.close()

print(f"\n拆分完成!共拆分为 {source.page_count} 个文件")

注意:上面的代码需要当前目录中存在 big.pdf 文件。在实际使用中,请替换为你自己的 PDF 文件路径。

9. PDF 转图片:将 PDF 页面转换为图片 #

PyMuPDF 可以将 PDF 页面转换为图片(PNG 或 JPG),这对于预览 PDF 内容或创建缩略图非常有用。

9.1 PDF 页面转图片 #

方法/类 功能说明 常用参数 返回值
fitz.Matrix() 创建变换矩阵(用于缩放) sx, sy:X 和 Y 方向的缩放因子 Matrix 对象
.get_pixmap() 将页面渲染为图片对象 matrix:变换矩阵(可选) Pixmap 对象
.save() 保存图片到文件 filename:文件路径 无
# -*- coding: utf-8 -*-
# 说明:演示如何将 PDF 页面转换为图片

# 说明:导入 fitz 模块和 os 模块
import fitz
import os

# 说明:定义转换函数
def pdf_to_images(pdf_path: str, output_dir: str = "output_images", dpi: int = 150):
    """
    将 PDF 的每一页转换为图片

    参数:
        pdf_path (str): PDF 文件路径
        output_dir (str): 输出目录
        dpi (int): 图片分辨率(每英寸点数)
    """
    # 说明:创建输出目录(如果不存在)
    # os.makedirs() 创建目录,exist_ok=True 表示如果目录已存在不报错
    os.makedirs(output_dir, exist_ok=True)

    # 说明:打开 PDF 文档
    doc = fitz.open(pdf_path)

    # 说明:遍历每一页
    for page_number in range(doc.page_count):
        # 说明:获取当前页
        page = doc[page_number]

        # 说明:创建变换矩阵(用于缩放)
        # Matrix(sx, sy) 创建变换矩阵
        # dpi / 72 是将分辨率从点(point)转换为像素(pixel)
        # 72 点是 1 英寸,如果 dpi=150,则 150/72 就是缩放因子
        matrix = fitz.Matrix(dpi / 72, dpi / 72)

        # 说明:将页面渲染为图片对象
        # get_pixmap() 方法将页面渲染为 Pixmap 对象
        # matrix 参数指定缩放比例
        pix = page.get_pixmap(matrix=matrix)

        # 说明:保存图片
        # save() 方法将图片保存为文件
        # 文件名包含页码(从 1 开始)
        output_path = os.path.join(output_dir, f"page_{page_number + 1}.png")
        pix.save(output_path)

        print(f"已保存:{output_path}")

        # 说明:释放图片对象,释放内存
        pix = None

    # 说明:关闭文档
    doc.close()

    print(f"\n转换完成!共转换 {doc.page_count} 页")

# 说明:调用函数进行转换
# 如果文件存在,进行转换
if os.path.exists("document.pdf"):
    pdf_to_images("document.pdf", "output_images", dpi=150)
else:
    # 说明:创建一个示例 PDF 用于演示
    print("创建示例 PDF...")
    doc = fitz.open()
    page = doc.new_page()
    page.insert_text((72, 72), "示例 PDF 文档", fontsize=20)
    doc.save("document.pdf")
    doc.close()

    # 说明:转换示例 PDF
    pdf_to_images("document.pdf", "output_images", dpi=150)

10. 搜索和高亮:在 PDF 中搜索文本并添加高亮 #

PyMuPDF 可以在 PDF 中搜索文本,并添加高亮、下划线等注释。这对于标注重要内容非常有用。

10.1 搜索文本并添加高亮 #

方法 功能说明 常用参数 返回值
.search_for() 在页面中搜索文本 text:要搜索的文本 列表,包含匹配的矩形区域
.add_highlight_annot() 添加高亮注释 rect:要高亮的矩形区域 Annotation 对象
.add_underline_annot() 添加下划线注释 rect:要添加下划线的矩形区域 Annotation 对象
.update() 更新注释(应用更改) 无 无
# -*- coding: utf-8 -*-
# 说明:演示如何在 PDF 中搜索文本并添加高亮

# 说明:导入 fitz 模块
import fitz

# 说明:打开 PDF 文档
doc = fitz.open("example.pdf")

# 说明:要搜索的文本
search_text = "重要内容"

# 说明:遍历每一页,搜索并高亮文本
for page_number in range(doc.page_count):
    # 说明:获取当前页
    page = doc[page_number]

    # 说明:在页面中搜索文本
    # search_for() 方法在页面中搜索指定的文本
    # 返回一个列表,包含所有匹配文本的矩形区域
    areas = page.search_for(search_text)

    # 说明:如果有匹配的文本
    if areas:
        print(f"第 {page_number + 1} 页找到 {len(areas)} 处匹配")

        # 说明:遍历每个匹配的区域
        for rect in areas:
            # 说明:添加高亮注释
            # add_highlight_annot() 方法添加高亮注释
            # 参数是文本所在的矩形区域
            highlight = page.add_highlight_annot(rect)

            # 说明:设置高亮颜色(可选)
            # set_colors() 方法设置注释的颜色
            # stroke 参数设置高亮颜色(RGB 格式,值范围 0-1)
            highlight.set_colors(stroke=[1, 1, 0])  # 黄色高亮

            # 说明:更新注释,应用更改
            # update() 方法应用注释更改
            highlight.update()

            # 说明:添加下划线注释(可选)
            # add_underline_annot() 方法添加下划线注释
            underline = page.add_underline_annot(rect)
            underline.update()
    else:
        print(f"第 {page_number + 1} 页未找到匹配文本")

# 说明:保存修改后的文档
doc.save("annotated.pdf")

# 说明:关闭文档
doc.close()

print("\n高亮完成!已保存到:annotated.pdf")

10.2 添加文本注释 #

方法 功能说明 常用参数 返回值
.add_text_annot() 添加文本注释 point:注释位置坐标,text:注释文本,icon:图标类型(可选) Annotation 对象
.add_rect_annot() 添加矩形注释 rect:矩形区域 Annotation 对象
.set_colors() 设置注释的颜色 stroke:边框颜色(可选),fill:填充颜色(可选) 无
# -*- coding: utf-8 -*-
# 说明:演示如何添加文本注释和矩形注释

# 说明:导入 fitz 模块
import fitz

# 说明:打开 PDF 文档
doc = fitz.open("example.pdf")

# 说明:获取第一页
page = doc[0]

# 说明:添加文本注释
# add_text_annot() 方法在指定位置添加文本注释
# 参数:位置坐标 (x, y),注释文本,图标类型
# icon="Note" 表示使用便签图标
annot = page.add_text_annot((100, 100), "这是注释内容", icon="Note")

# 说明:设置注释颜色
# set_colors() 方法设置注释的颜色
# stroke 参数设置边框颜色(RGB 格式)
annot.set_colors(stroke=[0, 0, 1])  # 蓝色边框

# 说明:更新注释
annot.update()

# 说明:添加矩形注释
# fitz.Rect(x0, y0, x1, y1) 创建矩形区域
# add_rect_annot() 方法添加矩形注释
rect = fitz.Rect(50, 50, 150, 100)
rect_annot = page.add_rect_annot(rect)

# 说明:设置矩形注释的颜色
# stroke 参数设置边框颜色
rect_annot.set_colors(stroke=[1, 0, 0])  # 红色边框

# 说明:更新矩形注释
rect_annot.update()

# 说明:保存修改后的文档
doc.save("annot_with_rect.pdf")

# 说明:关闭文档
doc.close()

print("注释已添加!已保存到:annot_with_rect.pdf")

11. 实战案例:PDF 处理工具 #

下面是一个完整的实战案例,综合运用前面学到的知识,创建一个简单的 PDF 处理工具。

方法/属性 功能说明
fitz.open() 打开或创建 PDF 文档
.page_count 获取页数
.get_text() 提取文本
.get_images() 获取图片
.new_page() 创建新页面
.insert_text() 插入文本
.save() 保存文档
.close() 关闭文档
# -*- coding: utf-8 -*-
# 说明:实战案例 - PDF 处理工具
# 综合运用前面学到的所有知识,创建一个 PDF 处理工具

# 说明:导入所需的库
import fitz
import os
from datetime import datetime

def pdf_info(pdf_path: str):
    """
    显示 PDF 文件的基本信息

    参数:
        pdf_path (str): PDF 文件路径
    """
    # 说明:打开 PDF 文档
    doc = fitz.open(pdf_path)

    # 说明:获取基本信息
    print(f"文件名:{pdf_path}")
    print(f"页数:{doc.page_count}")
    print(f"文件大小:{os.path.getsize(pdf_path) / 1024:.2f} KB")

    # 说明:获取元数据
    print("\n元数据:")
    for key, value in doc.metadata.items():
        if value:
            print(f"  {key}:{value}")

    # 说明:统计文本和图片
    total_text_length = 0
    total_images = 0

    for page_number in range(doc.page_count):
        page = doc[page_number]
        text = page.get_text()
        total_text_length += len(text)
        images = page.get_images()
        total_images += len(images)

    print(f"\n统计信息:")
    print(f"  总文本长度:{total_text_length} 个字符")
    print(f"  总图片数:{total_images} 张")

    # 说明:关闭文档
    doc.close()

def extract_all_text(pdf_path: str, output_path: str):
    """
    提取 PDF 中的所有文本并保存到文件

    参数:
        pdf_path (str): PDF 文件路径
        output_path (str): 输出文件路径
    """
    # 说明:打开 PDF 文档
    doc = fitz.open(pdf_path)

    # 说明:提取所有文本
    all_text = []
    for page_number in range(doc.page_count):
        page = doc[page_number]
        text = page.get_text()
        all_text.append(f"=== 第 {page_number + 1} 页 ===\n{text}\n")

    # 说明:保存到文件
    with open(output_path, "w", encoding="utf-8") as f:
        f.write("\n".join(all_text))

    # 说明:关闭文档
    doc.close()

    print(f"文本已提取到:{output_path}")

def create_watermarked_pdf(source_path: str, watermark_text: str, output_path: str):
    """
    创建带水印的 PDF

    参数:
        source_path (str): 源 PDF 文件路径
        watermark_text (str): 水印文本
        output_path (str): 输出文件路径
    """
    # 说明:打开源 PDF
    doc = fitz.open(source_path)

    # 说明:遍历每一页,添加水印
    for page_number in range(doc.page_count):
        page = doc[page_number]

        # 说明:获取页面中心位置
        rect = page.rect
        center_x = rect.width / 2
        center_y = rect.height / 2

        # 说明:在页面中心插入水印文本
        # color 参数设置文本颜色为浅灰色
        # 可以调整透明度
        page.insert_text(
            (center_x - 50, center_y),
            watermark_text,
            fontsize=20,
            color=(0.8, 0.8, 0.8)  # 浅灰色
        )

    # 说明:保存带水印的 PDF
    doc.save(output_path)

    # 说明:关闭文档
    doc.close()

    print(f"带水印的 PDF 已保存到:{output_path}")

# 说明:主程序入口
if __name__ == "__main__":
    # 说明:创建一个示例 PDF 用于演示
    print("创建示例 PDF...")
    doc = fitz.open()
    page = doc.new_page()
    page.insert_text((72, 72), "这是示例 PDF 文档", fontsize=16)
    page.insert_text((72, 100), "包含重要内容", fontsize=12)
    doc.save("example_demo.pdf")
    doc.close()
    print("示例 PDF 已创建:example_demo.pdf\n")

    # 说明:显示 PDF 信息
    print("=" * 50)
    print("PDF 信息:")
    print("=" * 50)
    pdf_info("example_demo.pdf")

    # 说明:提取文本
    print("\n" + "=" * 50)
    print("提取文本:")
    print("=" * 50)
    extract_all_text("example_demo.pdf", "extracted_text.txt")

    # 说明:创建带水印的 PDF
    print("\n" + "=" * 50)
    print("创建带水印的 PDF:")
    print("=" * 50)
    create_watermarked_pdf("example_demo.pdf", "水印文本", "watermarked.pdf")

    print("\n处理完成!")

12. 常见问题与排查 #

在使用 PyMuPDF 时,可能会遇到一些常见问题。本节提供解决方案。

12.1 文件不存在错误 #

问题:打开 PDF 文件时提示文件不存在。

解决方案:

# -*- coding: utf-8 -*-
# 说明:演示如何处理文件不存在的情况

# 说明:导入 fitz 模块和 os 模块
import fitz
import os

# 说明:方法1:使用 try-except 捕获异常
pdf_path = "example.pdf"

try:
    # 说明:尝试打开 PDF 文件
    doc = fitz.open(pdf_path)
    print(f"成功打开:{pdf_path}")
    doc.close()
except FileNotFoundError:
    # 说明:如果文件不存在,捕获异常
    print(f"错误:文件 {pdf_path} 不存在")
except Exception as e:
    # 说明:捕获其他可能的错误
    print(f"错误:{e}")

# 说明:方法2:先检查文件是否存在
pdf_path = "example.pdf"

if os.path.exists(pdf_path):
    # 说明:文件存在,可以安全打开
    doc = fitz.open(pdf_path)
    print(f"成功打开:{pdf_path}")
    doc.close()
else:
    # 说明:文件不存在,提示用户
    print(f"错误:文件 {pdf_path} 不存在")
    print("请检查文件路径是否正确")

12.2 内存管理问题 #

问题:处理大文件时内存占用过高。

解决方案:

# -*- coding: utf-8 -*-
# 说明:演示如何正确处理大文件,避免内存泄漏

# 说明:导入 fitz 模块
import fitz

def process_large_pdf(pdf_path: str):
    """
    逐页处理大 PDF 文件(推荐方式)

    参数:
        pdf_path (str): PDF 文件路径
    """
    # 说明:打开 PDF 文档
    doc = fitz.open(pdf_path)

    # 说明:逐页处理,避免一次性加载所有页面
    for page in doc:
        # 说明:处理当前页
        text = page.get_text()

        # 说明:处理文本(这里只是示例)
        # 在实际应用中,可以对文本进行分析、提取等操作
        print(f"处理第 {page.number + 1} 页,文本长度:{len(text)}")

        # 说明:如果需要处理图片,也要及时释放
        images = page.get_images()
        for img in images:
            xref = img[0]
            pix = fitz.Pixmap(doc, xref)
            # 说明:处理图片...
            # 处理完后立即释放
            pix = None

    # 说明:处理完成后关闭文档
    doc.close()
    print("处理完成")

# 说明:调用函数
try:
    process_large_pdf("large.pdf")
except FileNotFoundError:
    print("文件不存在,创建示例文件...")
    # 说明:创建示例文件用于演示
    doc = fitz.open()
    for i in range(5):
        page = doc.new_page()
        page.insert_text((72, 72), f"第 {i+1} 页", fontsize=16)
    doc.save("large.pdf")
    doc.close()

    process_large_pdf("large.pdf")

12.3 中文显示问题 #

问题:提取的中文文本显示乱码。

解决方案:

# -*- coding: utf-8 -*-
# 说明:演示如何处理中文文本提取

# 说明:导入 fitz 模块
import fitz

# 说明:打开包含中文的 PDF
doc = fitz.open("chinese.pdf")

# 说明:提取文本
for page_number in range(doc.page_count):
    page = doc[page_number]

    # 说明:方法1:直接提取文本(通常可以正确处理中文)
    text = page.get_text()

    # 说明:如果出现乱码,可能需要指定编码
    # 大多数情况下,PyMuPDF 会自动处理编码

    # 说明:保存文本时指定 UTF-8 编码
    if text:
        print(f"第 {page_number + 1} 页文本:")
        print(text[:100])  # 只显示前 100 个字符

# 说明:关闭文档
doc.close()

print("\n提示:")
print("  - 如果中文显示乱码,确保文件保存时使用 UTF-8 编码")
print("  - 使用 open(file, 'w', encoding='utf-8') 打开文件进行写入")

13. 参考 #

  • PyMuPDF 官方文档
  • PyMuPDF GitHub
  • MuPDF 官方网站

访问验证

请输入访问令牌

Token不正确,请重新输入