基于RapidOCR与LangChain的PDF图文内容解析器开发

发布于:2025-07-02 ⋅ 阅读:(25) ⋅ 点赞:(0)
from typing import List
from langchain.document_loaders.unstructured import UnstructuredFileLoader
from document_loaders.ocr import get_ocr
import tqdm


class RapidOCRPDFLoader(UnstructuredFileLoader):
    def _get_elements(self) -> List:
        def pdf2text(filepath):
            import fitz # pyMuPDF里面的fitz包,不要与pip install fitz混淆
            import numpy as np
            ocr = get_ocr()
            doc = fitz.open(filepath)
            resp = ""

            b_unit = tqdm.tqdm(total=doc.page_count, desc="RapidOCRPDFLoader context page index: 0")
            for i, page in enumerate(doc):

                # 更新描述
                b_unit.set_description("RapidOCRPDFLoader context page index: {}".format(i))
                # 立即显示进度条更新结果
                b_unit.refresh()
                # TODO: 依据文本与图片顺序调整处理方式
                text = page.get_text("")
                resp += text + "\n"

                img_list = page.get_images()
                for img in img_list:
                    pix = fitz.Pixmap(doc, img[0])
                    img_array = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.height, pix.width, -1)
                    result, _ = ocr(img_array)
                    if result:
                        ocr_result = [line[1] for line in result]
                        resp += "\n".join(ocr_result)

                # 更新进度
                b_unit.update(1)
            return resp

        text = pdf2text(self.file_path)
        from unstructured.partition.text import partition_text
        return partition_text(text=text, **self.unstructured_kwargs)


if __name__ == "__main__":
    loader = RapidOCRPDFLoader(file_path="../tests/samples/ocr_test.pdf")
    docs = loader.load()
    print(docs)
from typing import TYPE_CHECKING


if TYPE_CHECKING:
    try:
        from rapidocr_paddle import RapidOCR
    except ImportError:
        from rapidocr_onnxruntime import RapidOCR


def get_ocr(use_cuda: bool = True) -> "RapidOCR":
    try:
        from rapidocr_paddle import RapidOCR
        ocr = RapidOCR(det_use_cuda=use_cuda, cls_use_cuda=use_cuda, rec_use_cuda=use_cuda)
    except ImportError:
        from rapidocr_onnxruntime import RapidOCR
        ocr = RapidOCR()
    return ocr

🧠 Langchain代码解析:

from langchain.document_loaders.unstructured import UnstructuredFileLoader
from unstructured.partition.text import partition_text

这两行代码分别导入了两个关键模块:

  1. UnstructuredFileLoader(来自 langchain
  2. partition_text(来自 unstructured

它们通常用于加载非结构化文本文件并将其转换为可用于下游任务(如向量化、问答系统等)的格式。


📦 第一部分:UnstructuredFileLoader

来源:

  • 属于 LangChain 库的一部分。
  • LangChain 是一个用于构建 LLM(大语言模型)应用的框架。
  • UnstructuredFileLoader 是其提供的一个文档加载器类。

功能:

将非结构化文本文件(如 .txt、.md、.csv 等)读取为 Document 对象。

Document 是 LangChain 中的一种标准数据结构,形式如下:

class Document:
    page_content: str  # 实际文本内容
    metadata: dict     # 元信息,如文件名、来源等

示例用法:

loader = UnstructuredFileLoader("example.txt")
documents = loader.load()

这会返回一个包含多个 Document 的列表,每个 Document 包含一页的内容和元信息。


📄 第二部分:partition_text

来源:

  • 属于 Unstructured 库。
  • Unstructured 是一个专门处理非结构化数据的开源库,支持多种文件格式(TXT, PDF, DOCX, HTML 等)。

功能:

对纯文本进行语义级别的切分(例如按段落、句子等),便于后续处理。

它能识别出文本中的标题、段落、项目符号等内容,并以结构化方式返回。

示例用法:

from unstructured.partition.text import partition_text

elements = partition_text(filename="example.txt")
for element in elements:
    print(element)

输出可能是:

Title: Introduction
NarrativeText: This is the first paragraph of the document.
ListItem: - First item
ListItem: - Second item

🔗 二者结合使用的意义

在实际应用中,你可以这样组合这两个模块:

from langchain.document_loaders.unstructured import UnstructuredFileLoader
from unstructured.partition.text import partition_text

# 自定义一个使用 partition_text 的 Loader
class CustomTextLoader(UnstructuredFileLoader):
    def _get_elements(self):
        return partition_text(filename=self.file_path)

# 使用自定义 Loader 加载文档
loader = CustomTextLoader("example.txt")
docs = loader.load()

📌 这样做的好处是:

  • 利用了 unstructured 强大的文本结构化解析能力
  • 同时兼容 LangChain 的接口,方便后续接入向量数据库、检索链、QA 链等功能

📌 总结一句话:

UnstructuredFileLoader 是 LangChain 中用于加载非结构化文件的标准工具,而 partition_text 是底层 unstructured 库中用于精细切分文本的方法,两者结合可以高效地将原始文本转化为结构化的文档对象,供 LLM 使用。



具体实现代码解析:RapidOCRPDFLoader

这是一个自定义的 PDF 文档加载器类,继承自 LangChain 的 UnstructuredFileLoader,用于读取 PDF 文件内容并将其转换为结构化文本格式,支持 OCR 图像识别。


🔍 导入部分

from typing import List
from langchain.document_loaders.unstructured import UnstructuredFileLoader
from document_loaders.ocr import get_ocr
import tqdm

解释:

模块 功能
List 用于类型注解,表示返回的是一个列表
UnstructuredFileLoader LangChain 提供的基类,用于将文件转为 Document 对象
get_ocr 自定义 OCR 工具函数(来自本地模块)
tqdm 显示进度条,提升用户体验

📦 类定义与初始化

class RapidOCRPDFLoader(UnstructuredFileLoader):
    def _get_elements(self) -> List:
  • 继承 UnstructuredFileLoader
  • 重写 _get_elements() 方法,这是所有 UnstructuredFileLoader 子类必须实现的方法。
  • 返回值是一个 List,包含从 PDF 中提取出的所有“元素”(如段落、标题等)

🧮 核心方法:pdf2text(filepath)

这个函数负责将 PDF 文件中的每一页转换为文本内容,并对图像执行 OCR 提取文字。

函数内部流程如下:

1️⃣ 引入依赖库

import fitz # PyMuPDF 的核心模块
import numpy as np
  • fitzPyMuPDF 的核心模块,用于处理 PDF 和图像
  • numpy 用于将图像像素数据转换为数组,便于 OCR 处理

2️⃣ 初始化 OCR 工具

ocr = get_ocr()
  • get_ocr() 是你项目中封装的 OCR 函数,可能调用了 PaddleOCR、EasyOCR 或其它 OCR 引擎

3️⃣ 打开 PDF 文件

doc = fitz.open(filepath)
resp = ""
  • 使用 fitz.open() 打开 PDF 文件
  • resp 用于拼接最终提取出的文本内容

4️⃣ 进度条设置

b_unit = tqdm.tqdm(total=doc.page_count, desc="RapidOCRPDFLoader context page index: 0")
  • 设置一个进度条,显示当前正在处理哪一页 PDF

5️⃣ 遍历 PDF 页面

for i, page in enumerate(doc):
    b_unit.set_description("RapidOCRPDFLoader context page index: {}".format(i))
    b_unit.refresh()
  • 遍历每一页 PDF
  • 更新进度条描述信息

6️⃣ 提取页面上的纯文本

text = page.get_text("")
resp += text + "\n"
  • page.get_text("") 提取当前页的纯文本内容
  • 添加到 resp 字符串中

7️⃣ 提取页面上的图片并执行 OCR

img_list = page.get_images()
for img in img_list:
    pix = fitz.Pixmap(doc, img[0])
    img_array = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.height, pix.width, -1)
    result, _ = ocr(img_array)
    if result:
        ocr_result = [line[1] for line in result]
        resp += "\n".join(ocr_result)
  • page.get_images() 获取该页所有图像对象
  • 将图像转换为 NumPy 数组 img_array,以便输入给 OCR
  • 调用 OCR 工具识别图像中的文字
  • 将识别结果添加到 resp

✅ 支持混合文本+图像的 PDF 内容提取

8️⃣ 更新进度条

b_unit.update(1)

📤 返回结果

return resp
  • 最终返回整个 PDF 提取后的完整文本字符串

📥 接下来:使用 partition_text 结构化解析

text = pdf2text(self.file_path)
from unstructured.partition.text import partition_text
return partition_text(text=text, **self.unstructured_kwargs)
  • 使用 unstructured 库提供的 partition_text 函数,对提取出的文本进行语义切分
  • 输出是多个结构化的“元素”,如:
    • Title
    • NarrativeText
    • ListItem
    • 等等

📌 这些结构化元素可以直接被 LangChain 的下游组件使用(如向量化、检索、QA Chain)


📌 示例运行

if __name__ == "__main__":
    loader = RapidOCRPDFLoader(file_path="../tests/samples/ocr_test.pdf")
    docs = loader.load()
    print(docs)
  • 实例化加载器
  • 加载 PDF 文件内容
  • 输出格式为 LangChain 的 Document 列表

示例输出可能是:

[
    Document(page_content='Introduction...', metadata={'source': 'ocr_test.pdf'}),
    Document(page_content='Section 1:...', metadata={'source': 'ocr_test.pdf'}),
    ...
]

✅ 总结一句话:

RapidOCRPDFLoader 是一个增强版的 PDF 加载器,它不仅能提取 PDF 中的文本,还能识别图像并执行 OCR,最后将内容结构化后返回,兼容 LangChain 的标准接口。



网站公告

今日签到

点亮在社区的每一天
去签到