RAG 的 PDF 文本怎么提取?用 PyMuPDF 保存页码、文本块和坐标

用 PyMuPDF 提取 RAG 用 PDF 的文本块,将文件哈希、页码、块号和坐标一起保存,并单独记录空文本页供回查。

给 RAG 知识库准备 PDF 文本时,除了文字,还应保存页码、文本块编号和坐标。这样检索命中后能回到原页核对,遇到双栏错序、页眉混入或扫描页也能定位来源。PyMuPDF 的 blocks 提取可以提供这些字段,但坐标排序不等于理解文档的阅读顺序。

本文处理读者有权使用的本地 PDF,不执行模型调用。以下接口依据为 2026 年 10 月 1 日读取的官方文档;复杂 PDF 的抽取质量需逐页核对,不能把一份教学文件的结果推广到全部文档。

RAG 的 PDF 文本怎么提取?用 PyMuPDF 保存页码、文本块和坐标

环境与输入范围

在独立 Python 环境安装 python -m pip install pymupdf==1.28.2。先拿一份小的、有可选择文字的 PDF,保存为 source.pdf。扫描页只有图片时,本例不会自动完成 OCR;加密文件、损坏页和复杂版式需要分别处理。

官方文字提取说明展示 page.get_text(“blocks”),并说明提取顺序可能受 PDF 的生成方式影响。本文使用 sort=True 形成坐标顺序,保留原始 block_no 供回查,不声称它能自动正确读取多栏论文或合并表格。

输出一个带出处的 JSONL

将代码保存为 pdf_blocks.py,执行 python pdf_blocks.py。它将当前文件版本的 SHA-256 与页号、块号放在同一记录中,并另外输出空文本页清单。

import hashlib
import json
from pathlib import Path
import pymupdf

source = Path("source.pdf")
digest = hashlib.sha256()
with source.open("rb") as stream:
    for piece in iter(lambda: stream.read(1024 * 1024), b""):
        digest.update(piece)
source_sha = digest.hexdigest()
empty_pages = []
count = 0

with pymupdf.open(source) as doc, Path("pdf_blocks.jsonl").open(
    "w", encoding="utf-8"
) as out:
    pages = len(doc)
    for page_index, page in enumerate(doc):
        found = 0
        for block in page.get_text("blocks", sort=True):
            x0, y0, x1, y1, text, block_no, block_type = block
            if block_type != 0 or not text.strip():
                continue
            record = {
                "source_file": source.name,
                "source_sha256": source_sha,
                "page": page_index + 1,
                "block_no": block_no,
                "bbox": [round(v, 3) for v in (x0, y0, x1, y1)],
                "text": text.strip(),
            }
            out.write(json.dumps(record, ensure_ascii=False) + "\n")
            count += 1
            found += 1
        if not found:
            empty_pages.append(page_index + 1)

summary = {"pages": pages, "text_blocks": count, "empty_pages": empty_pages}
Path("pdf_extract_summary.json").write_text(
    json.dumps(summary, ensure_ascii=False, indent=2), encoding="utf-8"
)
print(summary)
if not count:
    raise ValueError("没有提取到文本;先检查文件或安排 OCR")

官方 TextPage 输出说明给出块元组中的四个坐标、文本、block_no 和 block_type;类型 0 是文本。代码跳过图像块,避免把图像描述误当正文。坐标用于在原页定位,不能单凭矩形推断标题等级、表格单元格或段落语义。

核对三个输出,而不是只看文件生成

  1. 打开 summary,页数应与 PDF 阅读器一致。empty_pages 非空时逐页确认:是有意空白页、扫描页,还是提取失败,不能直接把这些页当作没有知识。
  2. 任选三个文本块,按 page 打开原页,核对 bbox 对应位置以及文字、数字、单位和否定词。页码按 1 起算,方便与阅读器对照。
  3. 检查页首/页尾与双栏页面,确认没有把相邻列错误拼成一个条款。无法可靠提取的页先保留为待处理,不送进自动回答链。

JSONL 中的 source_sha256 标识当前 PDF 的字节版本。同一文件修改后摘要会变化,page/block_no 也可能重排;它们不是跨版本不变的业务 ID。

如何用于 RAG,而不丢掉原文关系

后续切片时保留 source_sha256、page、block_no 和必要的坐标范围。一个片段如果合并多个块,应保存全部组成块的引用;不要只留合并后的字符串和向量,让读者再也无法回查原页。

块边界也不一定是合适的检索片段:标题与正文可能分成不同块,表格可能逐行拆开。先用实际问答任务检查片段是否有完整条件,再决定合并方式。本文只交付文本与出处,不自动判定分段策略或生成向量。

常见失败与下一步

  • 整页没有文本:对照 PDF 看是否是扫描图像,再选择 OCR,并保留 OCR 的来源和误识别记录。
  • 顺序不对:利用坐标定位列与区域,对当前版式制定规则;不要把 sort=True 当作通用阅读理解。
  • 表格数值混乱:按原页核对行列,必要时使用专门的表格提取及人工校验。
  • 提取过程中报错:保存文件版本和失败页,不能把部分输出标成完整导入。

先对小 PDF 运行一次,回查几个关键条款及所有空文本页。文字与出处都能对应,再将输出交给知识库的切片和索引环节。

Ai菜鸟网。发布者:AI小管家,转载请注明出处:https://www.alyyhw.com/31975.html

赞 (0)
AI小管家的头像AI小管家
Ollama 本地模型怎么输出 JSON?用 JSON Schema 提取字段并验证结果
上一篇 2小时前
RAG 检索候选怎么重排?用 CrossEncoder 打分并保留来源 ID
下一篇 2小时前

相关推荐

联系我们

联系我们

1

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
关注微信
分享本页
返回顶部