使用 PyMuPDF 和 pdfplumber 解析 PDF
以编程方式从 PDF 中提取文本、表格和元数据。
使用 PyMuPDF 和 pdfplumber 解析 PDF 是 CoddyKit 上的免费 AI Agents 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 AI Agents 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 AI Agents 课程共包含 4 节课。
为什么 PDF 解析并不简单
PDF 是一种展示格式,而不是数据格式。文本以带位置的字形存储,而不是逻辑段落。提取有意义的文本需要理解布局、阅读顺序和字体属性,并处理多栏布局、页眉/页脚以及嵌入图像等边界情况。
有两个库最为常用:PyMuPDF(速度快)和 pdfplumber(表格提取)。
PyMuPDF 基础
PyMuPDF(导入时使用 fitz)是速度最快的 Python PDF 库。它支持文本提取、元数据、图像和渲染。使用 pip install pymupdf 进行安装。
import fitz # PyMuPDF
# Open a PDF
doc = fitz.open('document.pdf')
print(f'Pages: {len(doc)}')
print(f'Metadata: {doc.metadata}')
# Extract text from all pages
full_text = ''
for page_num in range(len(doc)):
page = doc[page_num]
text = page.get_text() # plain text extraction
full_text += f'--- Page {page_num + 1} ---\n{text}\n'
doc.close()
print(full_text[:500])PyMuPDF 文本提取模式
page.get_text() 支持不同的输出格式。使用 'text' 获取纯文本,使用 'blocks' 获取带边界框的文本块,使用 'dict' 获取包含字体名称和大小等信息的丰富结构化输出。
import fitz
doc = fitz.open('report.pdf')
page = doc[0]
# Mode 1: plain text
plain = page.get_text('text')
# Mode 2: blocks (each block has bbox + text)
blocks = page.get_text('blocks')
for block in blocks:
x0, y0, x1, y1, text, block_no, block_type = block
if block_type == 0: # text block (1 = image)
print(f'Block at ({x0:.0f},{y0:.0f}): {text[:80]}')
# Mode 3: dict (full detail including font info)
page_dict = page.get_text('dict')
for block in page_dict['blocks']:
if block.get('type') == 0: # text
for line in block['lines']:
for span in line['spans']:
print(f"Font: {span['font']}, Size: {span['size']:.1f}, Text: {span['text']}")
doc.close()提取页面元数据
页面元数据有助于智能体理解文档结构,包括页数、文档标题、作者、创建日期和页面尺寸。PyMuPDF 提供了所有这些信息。
import fitz
def extract_pdf_metadata(filepath):
doc = fitz.open(filepath)
meta = doc.metadata
info = {
'title': meta.get('title', 'Unknown'),
'author': meta.get('author', 'Unknown'),
'subject': meta.get('subject', ''),
'creator': meta.get('creator', ''),
'created': meta.get('creationDate', ''),
'modified': meta.get('modDate', ''),
'pages': len(doc),
'page_size': {
'width': doc[0].rect.width,
'height': doc[0].rect.height
}
}
doc.close()
return info
meta = extract_pdf_metadata('contract.pdf')
print(f"Title: {meta['title']}, Pages: {meta['pages']}")使用 pdfplumber 提取表格
pdfplumber 擅长从 PDF 中提取表格。它使用几何分析来检测单元格边界,即使 PDF 没有明确的表格标记也可以处理。
使用 pip install pdfplumber 进行安装。
import pdfplumber
with pdfplumber.open('financial_report.pdf') as pdf:
for page_num, page in enumerate(pdf.pages):
tables = page.extract_tables()
for table_idx, table in enumerate(tables):
print(f'Page {page_num+1}, Table {table_idx+1}:')
# table is a list of rows; each row is a list of cell strings
headers = table[0]
for row in table[1:]:
row_dict = dict(zip(headers, row))
print(row_dict)pdfplumber 表格设置
可以通过设置调整 pdfplumber 的表格提取功能,以处理不同的表格样式:明确的线条、以空格分隔的列或混合布局。
import pdfplumber
# Custom table settings for borderless tables
table_settings = {
'vertical_strategy': 'text', # 'lines', 'lines_strict', 'text', 'explicit'
'horizontal_strategy': 'text',
'snap_tolerance': 5,
'join_tolerance': 3,
'edge_min_length': 50,
'min_words_vertical': 3,
'min_words_horizontal': 1
}
with pdfplumber.open('nolines_table.pdf') as pdf:
page = pdf.pages[0]
table = page.extract_table(table_settings)
if table:
import csv
import io
output = io.StringIO()
writer = csv.writer(output)
writer.writerows(table)
csv_string = output.getvalue()
print(csv_string[:300])处理多栏布局
学术论文和报纸经常使用多栏布局。简单的文本提取会从左到右跨栏读取,生成混乱的文本。可以先按列对文本块进行排序来解决这个问题。
import fitz
def extract_multicolumn_text(page, n_columns=2):
page_width = page.rect.width
col_width = page_width / n_columns
blocks = page.get_text('blocks')
# Filter text blocks only
text_blocks = [b for b in blocks if b[6] == 0]
# Assign each block to a column based on x position
columns = [[] for _ in range(n_columns)]
for block in text_blocks:
x0 = block[0]
col_idx = min(int(x0 / col_width), n_columns - 1)
columns[col_idx].append(block)
# Sort each column by vertical position
for col in columns:
col.sort(key=lambda b: b[1]) # sort by y0
# Read columns left to right
full_text = ''
for col in columns:
for block in col:
full_text += block[4] + '\n'
return full_text筛除页眉和页脚
PDF 的页眉和页脚会在每一页重复,从而污染提取出的文本。可以根据它们的垂直位置(页面顶部或底部的 10%)识别这些内容,并在提取内容时将其排除。
import fitz
def extract_without_headers_footers(page, margin_ratio=0.08):
page_height = page.rect.height
top_margin = page_height * margin_ratio
bottom_margin = page_height * (1 - margin_ratio)
blocks = page.get_text('blocks')
content_blocks = []
for block in blocks:
x0, y0, x1, y1, text, block_no, block_type = block
if block_type != 0:
continue # skip image blocks
# Skip blocks in header or footer zone
if y0 < top_margin or y1 > bottom_margin:
continue
content_blocks.append(text)
return '\n'.join(content_blocks)为智能体分块处理 PDF 文本
较长的 PDF 必须拆分成多个文本块,才能进行嵌入和检索。请在自然边界处分块,例如段落、章节或页面之间。让相邻文本块之间保留一定重叠,避免在句子中间截断上下文。
import fitz
def pdf_to_chunks(filepath, chunk_size=1000, overlap=200):
doc = fitz.open(filepath)
chunks = []
for page_num in range(len(doc)):
page = doc[page_num]
page_text = page.get_text()
# Split into chunks with overlap
start = 0
while start < len(page_text):
end = start + chunk_size
chunk = page_text[start:end]
chunks.append({
'text': chunk,
'page': page_num + 1,
'char_start': start,
'source': filepath
})
start += chunk_size - overlap # overlap
doc.close()
return chunks
chunks = pdf_to_chunks('research_paper.pdf')
print(f'Total chunks: {len(chunks)}')
print(f'Sample: {chunks[0]["text"][:200]}')结合 PyMuPDF 与 PDF 表格解析器
使用 PyMuPDF 提取文本(速度更快),使用 PDF 表格解析器检测表格(准确度更高)。组合提取器会处理每一页,同时运行这两种提取方式,并返回结构化内容,将文本和表格分开。
import fitz
import pdfplumber
def full_pdf_extract(filepath):
result = {'text_by_page': [], 'tables': []}
# Text extraction with PyMuPDF
doc = fitz.open(filepath)
for i in range(len(doc)):
text = extract_without_headers_footers(doc[i])
result['text_by_page'].append({'page': i + 1, 'text': text})
doc.close()
# Table extraction with pdfplumber
with pdfplumber.open(filepath) as pdf:
for page_num, page in enumerate(pdf.pages):
tables = page.extract_tables()
for t in tables:
result['tables'].append({
'page': page_num + 1,
'headers': t[0] if t else [],
'rows': t[1:] if t and len(t) > 1 else []
})
return result将提取的文本保存到文件
从 PDF 提取文本后,请将其保存为下游智能体可以使用的格式。纯文本文件非常适合嵌入流程;JSON 则可以保留页面结构,便于追踪引用。
import json, os
class FakePage:
def __init__(self, text): self.text = text
def get_text(self): return self.text
class FakeDoc(list):
def close(self): pass
def fitz_open(path):
return FakeDoc([FakePage('Page 1 text'), FakePage('Page 2 text')])
def pdf_to_text_file(pdf_path, output_dir):
doc = fitz_open(pdf_path)
base = os.path.splitext(os.path.basename(pdf_path))[0]
txt_path = os.path.join(output_dir, base + '.txt')
with open(txt_path, 'w', encoding='utf-8') as f:
for i, page in enumerate(doc):
f.write(f'--- Page {i+1} ---\n{page.get_text()}\n')
json_path = os.path.join(output_dir, base + '.json')
pages = [{'page': i+1, 'text': p.get_text()} for i, p in enumerate(doc)]
with open(json_path, 'w') as f:
json.dump({'source': pdf_path, 'pages': pages}, f, indent=2)
doc.close()
print(f'Saved: {txt_path} and {json_path}')
return txt_path, json_path
pdf_to_text_file('sample.pdf', '.')知识检查
哪个 Python 库最适合从 PDF 文件中提取表格?
回顾:使用 PyMuPDF 和 PDF 表格解析器解析 PDF
PyMuPDF(fitz)是提取文本和元数据,以及处理多栏布局的快速选择。PDF 表格解析器擅长提取表格,并支持配置几何策略。
关键技术包括:使用 get_text('blocks') 进行与位置相关的提取;根据垂直位置过滤页眉和页脚;通过按列对文本块排序来处理多栏布局;以及为智能体检索系统创建带重叠的文本块。结合使用这两个库可以获得最佳效果。
用 AI 导师学习 AI Agents — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 60
- 课程
- 239
常见问题解答
「使用 PyMuPDF 和 pdfplumber 解析 PDF」课时是免费的吗?
是的 — 「使用 PyMuPDF 和 pdfplumber 解析 PDF」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 AI Agents 课程的其余内容,请升级到 CoddyKit PRO。 AI Agents 课程共包含 4 节课。
「使用 PyMuPDF 和 pdfplumber 解析 PDF」这节课中我会学到什么?
以编程方式从 PDF 中提取文本、表格和元数据。 你通过在浏览器中直接运行的动手代码来练习 AI Agents,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 AI Agents 需要有经验吗?
无需任何先前经验。CoddyKit 上的 AI Agents 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「使用 PyMuPDF 和 pdfplumber 解析 PDF」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 AI Agents 课中编写并运行代码吗?
能。每节 AI Agents 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。