Python PDF 库 — 10 行代码上手 PDF Oxide
PDF Oxide 是目前最快的 Python PDF 库:文本提取平均每页 0.8 ms,比 PyMuPDF 快 5 倍,在 3830 个测试 PDF 上保持 100% 通过率。一个库搞定提取、生成、编辑。MIT 协议,Rust 内核,无系统依赖。
安装
pip install pdf_oxide
**环境要求:**Python 3.8 及以上。Linux、macOS、Windows 的 x86_64 与 ARM64 架构均提供预编译 wheel,无需编译器或系统依赖。
打开 PDF
用 PdfDocument 打开任意 PDF 并查看基本信息。
from pdf_oxide import PdfDocument
doc = PdfDocument("research-paper.pdf")
print(f"Pages: {doc.page_count()}")
print(f"PDF version: {doc.version()}")
页面 API
从 v0.3.34 开始,PdfDocument 可迭代、可索引,返回带懒加载属性的 PdfPage 对象。
from pdf_oxide import PdfDocument
with PdfDocument("paper.pdf") as doc:
for page in doc: # len(doc)、doc[i]、doc[-1] 均可用
text = page.text # 懒加载 — 访问时才计算
md = page.markdown(detect_headings=True)
for table in page.tables:
for row in table["rows"]:
print([cell["text"] for cell in row["cells"]])
页面属性(全部懒加载):text、chars、words、lines、spans、tables、images、paths、annotations、width、height、bbox。方法:markdown()、plain_text()、html()、render()、search()、region(x, y, w, h)。
v0.3.34 中,编辑器的页面类已重命名为
EditorPage,避免与PdfPage冲突。
文本提取
单页
通过从 0 开始的页索引提取页面的纯文本。
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
text = doc.extract_text(0)
print(text)
全部页面
from pdf_oxide import PdfDocument
doc = PdfDocument("book.pdf")
for i in range(doc.page_count()):
text = doc.extract_text(i)
print(f"--- Page {i + 1} ---")
print(text)
字符级提取
extract_chars() 返回页面上每个字符的 TextChar 列表,包含精确位置和字体元数据。
from pdf_oxide import PdfDocument
doc = PdfDocument("paper.pdf")
chars = doc.extract_chars(0)
for ch in chars[:10]:
print(f"'{ch.char}' at ({ch.x:.1f}, {ch.y:.1f}) "
f"size={ch.font_size:.1f} font={ch.font_name} "
f"bbox={ch.bbox}")
每个 TextChar 包含以下字段:
| 字段 | 类型 | 说明 |
|---|---|---|
char |
str |
Unicode 字符 |
x |
float |
水平坐标(点) |
y |
float |
垂直坐标(点) |
font_size |
float |
字号(点) |
font_name |
str |
PostScript 字体名 |
bbox |
tuple[float, 4] |
包围盒 (x0, y0, x1, y1) |
文本 Span
extract_spans() 将字体与字号相同的连续字符合并为 span,返回带字体元数据的结构化文本。
from pdf_oxide import PdfDocument
doc = PdfDocument("paper.pdf")
spans = doc.extract_spans(0)
for span in spans:
print(f"'{span.text}' font={span.font_name} size={span.font_size}")
Markdown 转换
将 PDF 页面转为 Markdown,可选启用标题识别。
from pdf_oxide import PdfDocument
doc = PdfDocument("paper.pdf")
md = doc.to_markdown(0, detect_headings=True)
print(md)
HTML 转换
将 PDF 页面转为 HTML。
from pdf_oxide import PdfDocument
doc = PdfDocument("paper.pdf")
html = doc.to_html(0)
print(html)
图像提取
extract_images() 返回页面中每张嵌入图像的 ImageInfo 列表,包含内容流中的图像以及嵌套 Form XObject 内的图像。
from pdf_oxide import PdfDocument
doc = PdfDocument("brochure.pdf")
images = doc.extract_image_bytes(0)
for i, img in enumerate(images):
print(f"Image {i}: {img['width']}x{img['height']} "
f"({len(img['data'])} bytes)")
with open(f"image_{i}.{img['format']}", "wb") as f:
f.write(img["data"])
extract_image_bytes() 返回的每个 dict 包含以下键:
| 键 | 类型 | 说明 |
|---|---|---|
width |
int |
图像宽度(像素) |
height |
int |
图像高度(像素) |
data |
bytes |
原始图像数据 |
format |
str |
图像格式(如 png、jpeg) |
从字节打开
从内存字节打开 PDF — 适用于从 S3、HTTP 或数据库下载的场景:
from pdf_oxide import PdfDocument
doc = PdfDocument.from_bytes(pdf_bytes)
text = doc.extract_text(0)
# 同样支持密码:
doc = PdfDocument.from_bytes(pdf_bytes, password="secret")
对于构建器 API:
from pdf_oxide import Pdf
pdf = Pdf.from_bytes(existing_pdf_bytes)
pdf.save("modified.pdf")
密码保护的 PDF
在构造函数中传入 password= 即可打开加密文档。
from pdf_oxide import PdfDocument
doc = PdfDocument("confidential.pdf", password="secret")
text = doc.extract_text(0)
print(text)
也可以在打开后再调用 doc.authenticate(password)。
创建 PDF
Pdf 类提供了从多种源格式创建 PDF 的工厂方法。
从 Markdown
from pdf_oxide import Pdf
pdf = Pdf.from_markdown("# Hello World\n\nThis is a PDF.")
pdf.save("output.pdf")
从 HTML
from pdf_oxide import Pdf
pdf = Pdf.from_html("<h1>Invoice</h1><p>Amount due: $42.00</p>")
pdf.save("invoice.pdf")
从纯文本
from pdf_oxide import Pdf
pdf = Pdf.from_text("Plain text document.\n\nSecond paragraph.")
pdf.save("notes.pdf")
从图像
from pdf_oxide import Pdf
pdf = Pdf.from_image("scan.jpg")
pdf.save("scan.pdf")
搜索
在整个文档或单一页面内检索文本。
from pdf_oxide import PdfDocument
doc = PdfDocument("manual.pdf")
# 检索全部页面
results = doc.search("configuration")
for r in results:
print(f"Page {r.page}: '{r.text}' at ({r.x:.0f}, {r.y:.0f})")
# 检索单个页面
page_results = doc.search_page(0, "configuration")
错误处理
PDF Oxide 针对 PDF 专属错误抛出 PdfError,I/O 问题则使用 Python 标准异常。
from pdf_oxide import PdfDocument, PdfError
try:
doc = PdfDocument("document.pdf")
text = doc.extract_text(0)
except PdfError as e:
print(f"PDF error: {e}")
except FileNotFoundError:
print("File not found")