Skip to content

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"]])

页面属性(全部懒加载):textcharswordslinesspanstablesimagespathsannotationswidthheightbbox。方法: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 图像格式(如 pngjpeg

从字节打开

从内存字节打开 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")

下一步