Python PDF内容提取全攻略:文本、表格、OCR与元数据实战

沈亦白
沈亦白
发布时间:2026-10-12 | 2人浏览过
原创

本文系统梳理Python提取PDF内容的完整方案,涵盖pypdf、pdfplumber、PyMuPDF、Camelot及OCRmyPDF等主流工具。详解文本与坐标级提取、表格识别(lattice/stream模式)、扫描件OCR转换、图片/链接/注释/表单及元数据读取。提供批量处理、清洗分块及RAG对接的实战代码与常见坑避坑指南,助力知识库构建与自动化处理。

导语

你是否希望一次性从PDF中获取文本、表格、图片、注释/表单、附件及元数据?本教程将手把手教你使用Python构建完整的“PDF内容抽取”流程:pypdf、pdfminer.six、pdfplumber、PyMuPDF、Camelot/tabula-py、pypdfium2、pikepdf、OCRmyPDF/Tesseract、Apache Tika 等主流方案全覆盖,包含可运行代码、实战参数与常见陷阱。该方案适用于知识库构建、合同/发票解析、RAG/向量化、数据标注及自动化批处理,可无缝对接 ChatGPT / Claude / Gemini / Perplexity / Kimi / 通义千问 / Copilot 等AI搜索与问答系统。

  • “如何用Python精确按坐标提取PDF指定区域(如页眉、表格或签名栏)的示例代码?”
  • “扫描件PDF如何通过OCRmyPDF转换为可检索格式,再使用pdfplumber抽取文本与表格?”
  • “PyMuPDF导出图片、链接及注释的最简代码(含CMYK转RGB处理)?”
  • “Camelot中lattice与stream模式如何选择?导出CSV/JSON的最佳实践是什么?”
  • “如何将PDF文本分块并清理(去除页眉、断词、连字符),以用于RAG向量化?”

使用Python全面提取PDF:文本、表格、图片、注释/表单、附件、元数据与OCR;覆盖pypdf、pdfminer.six、pdfplumber、PyMuPDF、Camelot、Tika等方案,附可运行代码与实战技巧

这篇文章能帮你解决什么?

  • PDF文本提取(保持阅读顺序/坐标)
  • 表格识别(网格/无网格、CSV/JSON导出)
  • 图片与矢量导出、链接/书签/注释/表单/附件/元数据读取
  • 扫描件OCR ➜ 可检索PDF / 纯文本回收
  • 大批量与性能优化:并行、缓存、降噪、重试、混合文档策略
  • RAG/AI应用对接:清洗、分块、Embedding、索引与检索评估
  • Python如何区分“数字生码PDF”和“扫描件PDF”,并自动走OCR?
  • 保持布局情况下抽取文本,用哪套库更稳?
  • 表格无边框时,Camelot如何调参提高召回?
  • 如何读取PDF表单字段与附件?
  • 大量PDF的并行与容错怎么做?

下面正文将按“快速选型 → 环境准备 → 方案与代码 → OCR → 表格 → 附件/元数据/注释/表单 → 区域抽取 → 清洗与性能 → 常见坑 → 通用脚手架”的顺序展开。

一、快速选型:你的目标 ➜ 用哪套库

需求/场景推荐库(主力)备选/增强
纯文本(快速/易用)pypdfPyMuPDF(速度快、格式多) (pypdf.readthedocs.io)
保留布局/坐标、精细控制pdfminer.six / pdfplumberPyMuPDF(blocks/dict/html) (pdfminersix.readthedocs.io)
表格抽取(文本型 PDF)Camelot(lattice/stream)tabula-py(Java 依赖) (camelot-py.readthedocs.io)
图片/矢量/链接/注释/书签PyMuPDFpypdf(注释、附件等)、pypdfium2(PDFium) (pymupdf.readthedocs.io)
附件/元数据/表单pypdf(附件/表单)pikepdf(XMP/DocInfo 元数据) (pypdf.readthedocs.io)
扫描件(图片为主)OCROCRmyPDF(整件管道)pdf2image + pytesseract(纯 Python 组合) (ocrmypdf.readthedocs.io)
通用解析(多格式统一接口)Apache Tika(tika-python / 客户端)适合“什么格式都有”的场景 (tika.apache.org)
高性能渲染/文本搜索(底层)pypdfium2(PDFium 绑定)需要渲染、文本范围/搜索 API 时更强 (pypdfium2.readthedocs.io)

二、环境准备

# 常用
pip install pypdf pdfminer.six pdfplumber pymupdf

# 表格
pip install "camelot-py[base]"     # 1.0+ 默认用 PDFium,无需 Ghostscript(Linux 下更易装):contentReference[oaicite:8]{index=8}
pip install tabula-py               # 需 Java 8+ 运行环境 :contentReference[oaicite:9]{index=9}

# OCR 路线1:一站式
# macOS 可: brew install ocrmypdf ;Linux/Win 请看文档 :contentReference[oaicite:10]{index=10}

# OCR 路线2:Python 组合
pip install pdf2image pytesseract   # 还需安装 Poppler 与 Tesseract 可执行文件 :contentReference[oaicite:11]{index=11}

# 深入与底层
pip install pypdfium2 pikepdf       # PDFium 绑定 & 元数据/结构 :contentReference[oaicite:12]{index=12}

三、方案详解 + 最少代码

1)pypdf:三行出文本,简单稳定

适合“生码PDF”(可选中文/英文本,非扫描图)。

from pypdf import PdfReader

reader = PdfReader("input.pdf")
text = "\n".join((page.extract_text() or "") for page in reader.pages)
print(text)

extract_text() 可加方向过滤(如只取正向文字):page.extract_text(0)。

优点:零依赖、API简洁;可读表单、注释、附件、书签等(见后文)。 不足:遇到复杂排版/多栏/间距依赖时,阅读顺序可能需要后处理。

2)pdfminer.six / pdfplumber:坐标级控制,布局友好

  • pdfminer.six:获取字符/行/字体/坐标,完全可控。
  • pdfplumber:基于pdfminer.six,更易取表格/文本块,可按区域裁剪、调参提取。

pdfminer.six:遍历页面元素

from pdfminer.high_level import extract_pages
from pdfminer.layout import LTTextContainer, LTChar, LAParams

for page_layout in extract_pages("input.pdf", laparams=LAParams()):
    for element in page_layout:
        if isinstance(element, LTTextContainer):
            print(element.get_text().strip())

pdfplumber:一页到手

import pdfplumber

with pdfplumber.open("input.pdf") as pdf:
    for i, page in enumerate(pdf.pages, 1):
        # 文本(可调 x/y 容差,提取更平滑)
        t = page.extract_text(x_tolerance=1, y_tolerance=3) or ""
        print(f"--- Page {i} ---\n{t}\n")

        # 表格(简单尝试)
        for table in page.extract_tables():
            for row in table:
                print(row)

pdfplumber自带可视调试与表格能力,文档与仓库示例很齐全。

3)PyMuPDF(fitz):速度快、输出多样(blocks/dict/html/json)

import fitz  # PyMuPDF

doc = fitz.open("input.pdf")
for page in doc:
    # “text”=纯文本;“blocks”=文本块;“dict/json/html”=结构化/富文本输出
    print(page.get_text("blocks"))
    links = page.get_links()          # 链接
    annots = [a.info for a in page.annots() or []]  # 注释

可选sort=True以更接近阅读顺序;支持导出HTML/JSON以保布局。

提取嵌入图片

import fitz
doc = fitz.open("input.pdf")
for page_index, page in enumerate(doc):
    for img in page.get_images(full=True):
        xref = img[0]
        pix = fitz.Pixmap(doc, xref)
        if pix.n > 4:   # CMYK等转RGB
            pix = fitz.Pixmap(fitz.csRGB, pix)
        pix.save(f"img_p{page_index}_{xref}.png")

(对图像导出,PyMuPDF通常最省心。)

4)表格抽取:Camelot / tabula-py

Camelot(推荐)

  • 两种算法:lattice(线框网格)/ stream(对齐间距);
  • 1.0+版本默认以pypdfium2(PDFium)作为图像转换后端,安装更轻量。
import camelot

# 自动模式(按页号),尝试 lattice 或 stream
tables = camelot.read_pdf("tables.pdf", pages="1-3", flavor="lattice")
print(tables.n)                 # 抽到了多少张表
df = tables[0].df               # 直接拿 pandas.DataFrame
tables.export("out.csv", f="csv", compress=True)

tabula-py(Java背后的Tabula) 需要Java 8+,长文档/批处理也很稳。

import tabula
dfs = tabula.read_pdf("tables.pdf", pages="all", multiple_tables=True)

5)扫描件OCR:两条路线

A. 一站式:OCRmyPDF(强烈推荐) 命令行即可:自动旋转、去倾斜、并行、生成可检索PDF/A。

ocrmypdf -l chi_sim+eng --rotate-pages --deskew input_scan.pdf searchable.pdf
  • 已有文字的页面可--skip-text,混合文档也轻松处理。

B. 纯Python组合:pdf2image + pytesseract

from pdf2image import convert_from_path
import pytesseract

pages = convert_from_path("scan.pdf", dpi=300)  # 依赖 Poppler
full_text = []
for img in pages:
    txt = pytesseract.image_to_string(img, lang="chi_sim+eng")
    full_text.append(txt)
print("\n".join(full_text))

pdf2image基于Poppler的pdftoppm/pdftocairo;pytesseract是Tesseract的Python包装。

小贴士:若仅想“先OCR成可检索PDF再抽文本”,用OCRmyPDF生成searchable.pdf,再用pypdf/pdfplumber/PyMuPDF抽取,质量更稳。

6)通用解析:Apache Tika

面对“来啥解啥”的企业场景(PDF、Word、PPT、图片等),Tika提供统一REST/CLI。 Python可用tika-python或更现代的客户端。

from tika import parser
parsed = parser.from_file("input.pdf")
print(parsed["content"])     # 纯文本
print(parsed["metadata"])    # 元数据

7)pypdfium2:基于PDFium的渲染/文本搜索

需要更底层的文本范围/坐标搜索、渲染时很好用。

import pypdfium2 as pdfium

pdf = pdfium.PdfDocument("input.pdf")
page = pdf.get_page(0)
textpage = page.get_textpage()
# 搜索关键字,返回范围迭代器
for match in textpage.search("发票", match_case=False):
    # 获取该命中范围的包围盒(可高亮/裁剪区域抽取)
    rect = textpage.get_rect(match)
    print(rect.left, rect.top, rect.right, rect.bottom)

API参见PdfPage.get_textpage()与PdfTextPage.search()。

8)附件、元数据、表单、注释、书签

附件(File Attachments) – pypdf

from pypdf import PdfReader

reader = PdfReader("has_attachments.pdf")
for name, blobs in reader.attachments.items():
    for i, content in enumerate(blobs):
        with open(f"{name}-{i}", "wb") as f:
            f.write(content)

表单(AcroForm) – pypdf / PyMuPDF

# pypdf:读表单域与值
from pypdf import PdfReader
reader = PdfReader("form.pdf")
fields = reader.get_fields()        # 或 reader.get_form_text_fields()
print(fields)

PyMuPDF把表单视为Widget注释,可遍历/读写

注释(Annotations) – pypdf / PyMuPDF

# pypdf 读取注释类型与位置
from pypdf import PdfReader
r = PdfReader("annotated.pdf")
for page in r.pages:
    if "/Annots" in page:
        for a in page["/Annots"]:
            obj = a.get_object()
            print(obj["/Subtype"], obj["/Rect"])

(官方示例涵盖多种注释类型:Text/Link/Highlight…)

元数据(XMP / DocumentInfo) – pikepdf

import pikepdf
pdf = pikepdf.open("input.pdf")
print(pdf.docinfo)            # 旧式 DocumentInfo(PDF 2.0 已废弃但仍常见)
meta = pdf.open_metadata()    # XMP 元数据
print(meta)

pikepdf清晰区分并统一接口管理元数据。

四、区域抽取(ROI):只要页面某块内容

pdfplumber最顺手:

import pdfplumber

with pdfplumber.open("input.pdf") as pdf:
    page = pdf.pages[0]
    # bbox = (x0, top, x1, bottom) ,单位:PDF points
    region = page.within_bbox((72, 72, 540, 200))
    print(region.extract_text())

(配合pypdfium2/PyMuPDF的搜索坐标,可先定位关键词,再扩大/偏移bbox抽取。)

五、后处理与清洗(实战很关键)

  • 连字符断行:合并“hyphen- \n ated” → “hyphenated”。
  • 页眉/页脚去重:按坐标或正则在每页顶部/底部裁剪或丢弃重复块。
  • 阅读顺序:PyMuPDFget_text("text", sort=True);pdfplumber调整x/y_tolerance。
  • Unicode规范化:unicodedata.normalize("NFKC", text),处理合字/全半角。
  • 表格后处理:对齐合并、空白列过滤、数值类型转换。

六、性能与稳定性

  • 分页流式处理:逐页读取写出,避免一次性载入整本PDF。
  • 并行:OCRmyPDF天生支持多核;Python端建议多进程(PDFium不建议多线程并发调用)。
  • 缓存与重试:网络/共享盘批量处理时,失败页重试;保存中间文件(如OCR产物)。
  • 混合文档:OCRmyPDF的--skip-text能跳过已有文字页,提高质量/速度。

七、常见坑

  1. PDF是扫描图:先OCR再谈文本抽取(不要直接“图转文”就拿来分析)。
  2. 多栏/复杂版式:用blocks/html/json(PyMuPDF)或pdfplumber/pdfminer的坐标流。
  3. 表格识别失败:切换Camelotflavor(lattice↔stream),或改用tabula-py。
  4. tabula-py报错:缺Java环境。
  5. pdf2image报错:缺Poppler;Windows需额外安装。

八、一个“通用抽取器”脚手架(自动决策 + 结构化输出)

"""
功能:
1) 先用 pypdf 试文本;太少/失败 -> 判断可能是扫描件 -> 走 OCRmyPDF 或 pdf2image+pytesseract
2) 可选:Camelot 抽表、PyMuPDF 抽图片/链接/注释、pypdf 抽附件,pikepdf 取元数据
3) 输出 JSON:text/table/images/annotations/forms/attachments/metadata
"""
import json, os, subprocess, tempfile, shutil
from pypdf import PdfReader
import fitz

def is_text_pdf(path, min_chars=200):
    try:
        reader = PdfReader(path)
        s = "".join((p.extract_text() or "") for p in reader.pages[:5])
        return len(s.strip()) >= min_chars
    except Exception:
        return False

def ocr_if_needed(path):
    if is_text_pdf(path):
        return path  # 原样返回
    # 尝试用 OCRmyPDF(若未安装,可改为 pdf2image+pytesseract)
    out = os.path.join(tempfile.gettempdir(), f"ocr_{os.path.basename(path)}")
    try:
        subprocess.run(
            ["ocrmypdf", "--skip-text", "-l", "chi_sim+eng", path, out],
            check=True, capture_output=True
        )
        return out
    except Exception:
        return path  # 回退:继续用原文件(避免中断)

def extract_all(path):
    path = ocr_if_needed(path)
    result = {"text": "", "tables": [], "images": [], "links": [], "annots": [],
              "attachments": [], "metadata": {}, "forms": {}}

    # 1. 文本(pypdf)
    r = PdfReader(path)
    result["text"] = "\n".join((p.extract_text() or "") for p in r.pages)

    # 2. 附件与表单
    try:
        result["attachments"] = list(r.attachments.keys())
    except Exception:
        pass
    try:
        result["forms"] = r.get_fields() or {}
    except Exception:
        pass

    # 3. 元数据(pikepdf 可更全面,这里用 pypdf 的 DocInfo 兜底)
    try:
        result["metadata"] = dict(r.metadata or {})
    except Exception:
        pass

    # 4. 图片/链接/注释(PyMuPDF)
    doc = fitz.open(path)
    for i, page in enumerate(doc):
        # 图片
        for img in page.get_images(full=True):
            result["images"].append({"page": i+1, "xref": img[0], "width": img[2], "height": img[3]})
        # 链接
        for lk in page.get_links():
            result["links"].append({"page": i+1, **lk})
        # 注释
        for a in page.annots() or []:
            result["annots"].append({"page": i+1, **(a.info or {})})

    return result

if __name__ == "__main__":
    data = extract_all("example.pdf")
    print(json.dumps(data, ensure_ascii=False, indent=2))

九、更多进阶:你或许会用到的“技巧包”

  • 关键词高亮/定位后抽取:pypdfium2.PdfTextPage.search()得到命中范围和矩形框,结合PyMuPDF裁切/绘制高亮层。
  • 导出HTML/JSON:PyMuPDFget_text("html"/"json"),用于前端展示或保留样式。
  • 书签/目录:pypdfium2PdfDocument.get_toc()。(pypdfium2.readthedocs.io)
  • PDF/A合规存档:OCRmyPDF默认支持--output-type pdfa。(GitHub)

十、结语:选对工具 + 正确预处理 = 事半功倍

  • 数字生码PDF:优先pypdf(简洁)→ 复杂版式用pdfplumber/PyMuPDF。
  • 表格:先Camelot(两种flavor多试几次),再考虑tabula-py。
  • 扫描件:OCRmyPDF先做可检索,再常规抽取。
  • 企业通用:Tika做统一入口。
  • 高性能/底层:pypdfium2处理渲染与文本搜索坐标。

祝你PDF“挖矿”顺利!如果需要,我也可以把上面的脚手架改造成可安装的CLI小工具或批处理脚本。

以上就是使用Python提取和读取PDF文件中的内容全方案与示例代码的详细内容,更多关于Python提取和读取PDF内容的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表