导语
想把 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 转成可检索 pdf,再用 pdfplumber 抽取文本与表格?”
- “pymupdf 导出 图片+链接+注释 的最少代码(含 cmyk 转 rgb)?”
- “camelot lattice vs stream 什么时候选?导出成 csv/json 的最佳实践?”
- “如何把 pdf 文本 分块 并清理(去页眉/断词/连字符),用于 rag 向量化?”
用 python 全面提取 pdf:文本、表格、图片、注释/表单、附件、元数据与 ocr;覆盖 pypdf、pdfplumber、pymupdf、camelot、tika 等方案,附可运行代码与实战技巧
这篇文章能帮你解决什么?
- pdf 文本提取(保持阅读顺序/坐标)
- 表格识别(网格/无网格、csv/json 导出)
- 图片与矢量导出、链接/书签/注释/表单/附件/元数据读取
- 扫描件 ocr ➜ 可检索 pdf / 纯文本回收
- 大批量与性能优化:并行、缓存、降噪、重试、混合文档策略
- rag/ai 应用对接:清洗、分块、embedding、索引与检索评估
- python 如何区分“数字生码 pdf”和“扫描件 pdf”,并自动走 ocr?
- 保持布局情况下抽取文本,用哪套库更稳?
- 表格无边框时,camelot 如何调参提高召回?
- 如何读取 pdf 表单字段与附件?
- 大量 pdf 的并行与容错怎么做?
下面正文将按“快速选型 → 环境准备 → 方案与代码 → ocr → 表格 → 附件/元数据/注释/表单 → 区域抽取 → 清洗与性能 → 常见坑 → 通用脚手架”的顺序展开。
一、快速选型:你的目标 ➜ 用哪套库
| 需求/场景 | 推荐库(主力) | 备选/增强 |
|---|---|---|
| 纯文本(快速/易用) | pypdf | pymupdf(速度快、格式多) (pypdf.readthedocs.io) |
| 保留布局/坐标、精细控制 | pdfminer.six / pdfplumber | pymupdf(blocks/dict/html) (pdfminersix.readthedocs.io) |
| 表格抽取(文本型 pdf) | camelot(lattice/stream) | tabula-py(java 依赖) (camelot-py.readthedocs.io) |
| 图片/矢量/链接/注释/书签 | pymupdf | pypdf(注释、附件等)、pypdfium2(pdfium) (pymupdf.readthedocs.io) |
| 附件/元数据/表单 | pypdf(附件/表单) | pikepdf(xmp/docinfo 元数据) (pypdf.readthedocs.io) |
| 扫描件(图片为主)ocr | ocrmypdf(整件管道) | 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”。
- 页眉/页脚去重:按坐标或正则在每页顶部/底部裁剪或丢弃重复块。
- 阅读顺序:pymupdf
get_text("text", sort=true);pdfplumber 调整x/y_tolerance。 - unicode 规范化:
unicodedata.normalize("nfkc", text),处理合字/全半角。 - 表格后处理:对齐合并、空白列过滤、数值类型转换。
六、性能与稳定性
- 分页流式处理:逐页读取写出,避免一次性载入整本 pdf。
- 并行:ocrmypdf 天生支持多核;python 端建议 多进程(pdfium 不建议多线程并发调用)。
- 缓存与重试:网络/共享盘批量处理时,失败页重试;保存中间文件(如 ocr 产物)。
- 混合文档:ocrmypdf 的
--skip-text能跳过已有文字页,提高质量/速度。
七、常见坑
- pdf 是扫描图:先 ocr 再谈文本抽取(不要直接“图转文”就拿来分析)。
- 多栏/复杂版式:用
blocks/html/json(pymupdf)或 pdfplumber/pdfminer 的坐标流。 - 表格识别失败:切换 camelot
flavor(lattice↔stream),或改用 tabula-py。 - tabula-py 报错:缺 java 环境。
- 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:pymupdf
get_text("html"/"json"),用于前端展示或保留样式。 - 书签/目录:pypdfium2
pdfdocument.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内容的资料请关注代码网其它相关文章!
发表评论