编程学习网 > 编程语言 > Python > Python 处理 PDF 的神器:PyMuPDF,我现在基本不想再手搓了!
2026
08-31

Python 处理 PDF 的神器:PyMuPDF,我现在基本不想再手搓了!


一个 PDF 丢过来,要抽文字、找指定页、拆文件、转图片,最后还得重新合成。

这种活看着不难,真写起来最烦。换几个库来回倒数据不说,碰上页数多一点的文件,处理速度也容易让人怀疑人生。

我现在碰到 PDF 批处理,第一反应基本就是 PyMuPDF

安装也没什么花活:

pip install pymupdf

代码里直接:

import pymupdf
doc = pymupdf.open("contract.pdf")
print("页数:", doc.page_count)

PyMuPDF 能干的事情不少,文本提取、页面渲染、拆分、合并、加水印这些都在一个库里。官方文档里的 Page.get_text()Page.get_pixmap()Document.insert_pdf() 也是我平时最常碰的几个接口。

但我一般不会上来就写一个读取 PDF 并打印 Hello World”的例子,那种代码工作里基本没什么用。

假设现在有一批合同 PDF,要找出包含合同编号甲方的页面,把命中的页面单独抽出来。

我会这么写:

from pathlib import Path
import pymupdf

def pick_contract_pages(src_file: str, out_file: str):
    source = pymupdf.open(src_file)
    picked = pymupdf.open()
    for page_no, page in enumerate(source):
        text = page.get_text("text", sort=True)
        hit_contract = "合同编号" in text
        hit_party = "甲方" in text
        if not (hit_contract and hit_party):
            continue
        print(f"命中第 {page_no + 1} ")
        picked.insert_pdf(source, from_page=page_no, to_page=page_no)
    if picked.page_count == 0:
        print(f"没找到目标页:{Path(src_file).name}")
        return
    picked.save(out_file, garbage=4, deflate=True)
    picked.close()
    source.close()

pick_contract_pages(
    "incoming/customer_contract.pdf",
    "output/contract_pages.pdf"
)

这段代码我比较喜欢的一点,是不用先把 PDF 拆成十几个临时文件,再一个个合回去。

直接在内存里的新文档对象上 insert_pdf() 就行。

而且提取文本时,我通常会顺手加上 sort=TruePDF 里的文字存储顺序未必就是人眼看到的从上到下,官方文档也专门提醒过这个问题,sort=True 可以按页面位置重新排序。

不过这里有个坑。

如果你跑:

text = page.get_text("text")

结果发现:

''

先别怀疑编码。

我碰这种情况第一件事不是改 UTF-8,而是直接打开 PDF 看它到底是真文字,还是扫描图片。

纯扫描版 PDF 本身没有可提取的文本层,get_text() 自然拿不到你肉眼看到的字。PyMuPDF 的文本提取针对的是 PDF 中已有的文本内容,不会因为图片里看起来有字就自动变成文字。

这种文件要走 OCR,处理思路已经是另一回事了。

还有一个我用得很多的功能:PDF 转图片。

比如线上收到一个 PDF,反馈7 页排版错了。我一般懒得人工截图,直接把指定页面渲染出来:

import pymupdf

def export_preview(pdf_file: str, pages: list[int]):
    doc = pymupdf.open(pdf_file)
    for page_no in pages:
        if page_no < 1 or page_no > doc.page_count:
            print(f"跳过非法页码{page_no}")
            continue
        page = doc[page_no - 1]
        pix = page.get_pixmap(dpi=160, alpha=False)
        target = f"preview/page_{page_no}.png"
        pix.save(target)
        print("已生成:", target)
    doc.close()

export_preview("report.pdf", [1, 7, 12])

get_pixmap() 这东西挺实用,调 DPI 就能控制输出图片清晰度,没必要自己研究 PDF 怎么画到 Canvas 上。官方接口也直接支持通过 dpi 控制渲染分辨率。

还有一种需求我见得更多:月底十几个 PDF 报告,最后要拼成一个总文件。

这种我不会碰命令行工具,Python 几行就够了:

from pathlib import Path
import pymupdf

def merge_reports(folder: str, target: str):
    result = pymupdf.open()
    files = sorted(Path(folder).glob("*.pdf"))
    for pdf_file in files:
        current = pymupdf.open(pdf_file)
        if current.page_count == 0:
            current.close()
            continue
        result.insert_pdf(current)
        print(f"合并 {pdf_file.name}{current.page_count} ")
        current.close()
    if result.page_count:
        result.save(target, garbage=4, deflate=True)
    result.close()

merge_reports("monthly_reports", "output/monthly_all.pdf")

这里我会多留一个心眼:批量跑文件时,该 close() 的就关掉。

尤其是定时任务一次扫很多 PDF,文件句柄一直挂着,最后报错的时候,你很容易把锅甩给 PDF 文件损坏,实际上是自己的资源没释放。

PyMuPDF 给我的感觉不是“API 特别优雅,而是干活比较直接。

我要文字,就 get_text()

我要图片,就 get_pixmap()

我要拆页、拼页,就操作 Document

很多 PDF 需求根本没必要上来搞一套很重的处理链路。先看看 PyMuPDF 能不能直接做,十有八九,代码会比你预想得短。

以上就是“模块化笔记本电脑制造商Framework翻倍式提高价格 因为内存价格还在继续涨价的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。  

扫码二维码 获取免费视频学习资料

Python编程学习

查 看2022高级编程视频教程免费获取