news 2026/5/23 15:42:00

PDFLoader 中的 OCR 文字提取实现详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PDFLoader 中的 OCR 文字提取实现详解

1. 背景与动机

默认的langchain_community.document_loaders.PyPDFLoader虽然支持extract_images参数,但在某些场景下,它并不会自动将 OCR 识别后的文字合并到page_content中。为了确保能够百分之百提取出 PDF 页面中嵌入的图像文字(如电路图标签、截图文字等),我们采用了Mix-in (混合)模式:在保留原生文本层提取能力的同时,手动插入自定义的 OCR 处理流程。


2. 核心技术栈

  • pypdf: 用于底层的 PDF 页面解析和原始图片对象提取。
  • rapidocr-onnxruntime: 核心 OCR 引擎。
    • 优势:基于 ONNX Runtime,运行速度快,且不需要安装 Tesseract 等系统级组件,完全通过 Python 包分发。
  • Pillow (PIL): 用于处理从 PDF 中提取出的二进制图片数据。

3. 逻辑流程图 (Mermaid)

开始 load_file

初始化 PyPDFLoader

调用 loader.load 提取文本层

extract_images == True?

合并文本 & 返回 Document

进入 _enrich_with_ocr

初始化 RapidOCR 引擎

PdfReader 读取原始文件

遍历请求的页面

页面是否有图片?

提取图片数据 Bytes

RapidOCR 执行识别

将识别文字追加到 Page Content

跳过

所有页面处理完成?

结束


4. 代码深度讲解

4.1load_file方法:逻辑枢纽

load_file是外部调用的主入口,它负责协调文本提取和 OCR 增强。

defload_file(self,source:str,**kwargs)->Document:# ... 略过参数获取和日志打印# 1. 初始化 LangChain 的 PyPDFLoaderloader=PyPDFLoader(file_path=source,extract_images=extract_images,# 告诉底层库我们要处理图像password=password)# 2. 提取文本层 (Native Text Layer)# 这一步会利用 pypdf 提取 PDF 中原本就是文本的内容,返回一个 List[Document]documents=loader.load()# 3. 页面过滤# 如果用户指定了特定页面(如 pages=[10]),我们在这里进行筛选ifpages:filtered_docs=[]forpage_numinpages:idx=page_num-1if0<=idx<len(documents):filtered_docs.append(documents[idx])documents=filtered_docs# 4. 【关键步骤】OCR 文本增强# 如果 extract_images 为 True,则进入我们自定义的 OCR 流程ifextract_images:self._enrich_with_ocr(documents,source,pages)# 5. 内容合并# 将处理后的各页内容用 "--- Page Break ---" 标记拼接成一个完整的字符串combined_content="\n\n--- Page Break ---\n\n".join(doc.page_contentfordocindocuments)# 6. 返回结果# 返回一个包含完整文本和元数据的 Document 对象returnDocument(page_content=combined_content,metadata=metadata)

4.2_enrich_with_ocr方法:技术核心

该方法负责底层的图像提取和 OCR 识别。

A. 引擎延迟加载
try:fromrapidocr_onnxruntimeimportRapidOCR ocr_engine=RapidOCR()exceptImportError:# 如果没装包,优雅降级,打印警告logger.warning("rapidocr-onnxruntime not installed. Skipping OCR for images.")return

讲解:我们没有在文件顶部全局导入 RapidOCR,而是放在方法内部。这样如果用户不需要 OCR 功能,就不必承担加载庞大 OCR 模型的时间和内存开销。

B. 页面索引映射
reader=pypdf.PdfReader(source)# 使用原生 pypdf 读取# 如果指定了 [1, 3] 页,doc_page_indices 会变成 [0, 2]ifrequested_pages:doc_page_indices=[p-1forpinrequested_pages]else:doc_page_indices=list(range(len(documents)))

讲解:这是一个坑点。documents列表的长度取决于你加载了多少页。如果只加载了第 10 页,documents长度就是 1,索引是 0。但我们需要告诉pypdf去读取原文件的第 9 个索引。这段逻辑保证了“索引对位”。

C. 图片提取与 OCR
fori,page_idxinenumerate(doc_page_indices):page=reader.pages[page_idx]images=page.images# 获取页面所有图片对象ocr_texts=[]forimageinimages:# image.data 直接拿到图片的 Bytes 数据result,_=ocr_engine(image.data)ifresult:# RapidOCR 返回结果格式:[[[box], text, score], ...]# 我们通过列表推导式 line[1] 拿到纯文字部分text="\n".join([line[1]forlineinresult])iftext.strip():# 包装识别出的文字,打上标签ocr_texts.append(f"[Image Text]:\n{text}")

讲解:

  • 我们利用了pypdf6.x 版本的新特性,可以直接通过page.images访问图片。
  • image.data是内存中的字节流,避免了 IO 读写临时文件的损耗。
  • ocr_engine(image.data)是最核心的识别动作。
D. 就地修改(In-place Update)
ifocr_texts:# 将识别到的文字追加到对应 Document 对象的原有文本后面documents[i].page_content+="\n\n"+"\n\n".join(ocr_texts)

讲解:这种设计模式不会创建新的 Document 对象,而是直接修改传入的列表对象,节省了内存空间。


5. 完整代码参考

以下是src/loaders/pdf_loader.py中关键方法的完整实现:

5.1load_file方法

defload_file(self,source:str,**kwargs)->Document:try:extract_images=kwargs.get('extract_images',False)pages=kwargs.get('pages',None)password=kwargs.get('password',None)logger.info(f"Loading PDF:{source}")loader=PyPDFLoader(file_path=source,extract_images=extract_images,password=password)documents=loader.load()ifnotdocuments:raiseValidationError(message="PDF is empty",error_code="EMPTY_PDF",source=source)ifpages:filtered_docs=[]forpage_numinpages:idx=page_num-1if0<=idx<len(documents):filtered_docs.append(documents[idx])documents=filtered_docsifextract_images:self._enrich_with_ocr(documents,source,pages)combined_content="\n\n--- Page Break ---\n\n".join(doc.page_contentfordocindocuments)metadata=documents[0].metadata.copy()ifdocumentselse{}metadata.update({'source':source,'file_type':'pdf','total_pages':len(documents),'file_size':Path(source).stat().st_size})returnDocument(page_content=combined_content,metadata=metadata)exceptExceptionase:raiseValidationError(message=str(e),error_code="PDF_LOAD_ERROR",source=source)frome

6. 测试验证

为了验证 OCR 功能,我们编写了专门的测试用例来检查第 10 页(包含产品框图)的内容提取情况。

6.1 测试代码 (test/loaders/test_pdf_loader.py)

deftest_load_file_with_images(self,loader):"""Test loading file with image extraction enabled."""PAGE_NUM=10document=loader.load_file(PDF_PATH,extract_images=True,pages=[PAGE_NUM])assertlen(document.page_content)>0print(f"\n=== Page{PAGE_NUM}Content (Image Extraction Enabled) ===")print(document.page_content)

6.2 测试输出结果

2025-12-28 01:29:06.981 | DEBUG | src.loaders.pdf_loader:_enrich_with_ocr:162 - Added OCR text from 6 images to page 10 === Page 10 Content (Image Extraction Enabled) === | 1 - 产品介绍 图 1-1 昉·星光 2 产品框图(顶部视图) ... (原生文本) ... [Image Text]: StarFive VisionFive 2 AE 888 ...

7. 实现的优势

  1. 零系统依赖:完全通过 Python 包实现 OCR。
  2. 强制增强:弥补了PyPDFLoader默认对图片文字提取不力的问题。
  3. 精准映射:支持特定页面的 OCR 提取。

8. 依赖说明 (requirements.txt)

pypdf==6.5.0 Pillow==12.0.0 rapidocr-onnxruntime==1.4.4
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/15 4:09:22

C设计模式终极指南:GOF模式完整教程与最佳实践

C#设计模式终极指南&#xff1a;GOF模式完整教程与最佳实践 【免费下载链接】design-patterns-csharp Design Pattern Examples in C# 项目地址: https://gitcode.com/gh_mirrors/de/design-patterns-csharp 在当今软件开发领域&#xff0c;掌握C#设计模式是提升代码质量…

作者头像 李华
网站建设 2026/5/9 2:11:53

Jupytext实战指南:告别.ipynb文件版本控制困境的终极方案

Jupytext实战指南&#xff1a;告别.ipynb文件版本控制困境的终极方案 【免费下载链接】jupytext Jupyter Notebooks as Markdown Documents, Julia, Python or R scripts 项目地址: https://gitcode.com/gh_mirrors/ju/jupytext 还在为Jupyter Notebook的.ipynb文件在Gi…

作者头像 李华
网站建设 2026/4/30 21:08:36

Ring 0层虚拟串口驱动编程新手教程

手把手教你写一个Ring 0层虚拟串口驱动&#xff1a;从零开始的内核级通信实战你有没有遇到过这样的场景&#xff1f;一台工控机只有两个物理串口&#xff0c;却要同时连接PLC、传感器、扫码枪和调试终端&#xff1b;或者你想把老款只能通过COM端口通信的设备接入网络&#xff0…

作者头像 李华
网站建设 2026/5/10 11:25:06

终极指南:5步轻松玩转Doomcaptcha游戏化验证码

Doomcaptcha是一个革命性的游戏化验证码解决方案&#xff0c;将传统的枯燥验证码转变为《毁灭战士》风格的沉浸式游戏体验。这个开源项目让验证过程变得有趣且富有挑战性&#xff0c;彻底改变了用户对验证码的刻板印象。 【免费下载链接】doomcaptcha Captchas dont have to be…

作者头像 李华
网站建设 2026/5/22 22:49:33

星火应用商店:Linux桌面应用的完整解决方案指南

想要在Linux系统上轻松安装软件吗&#xff1f;星火应用商店为您提供了终极解决方案。这款国内领先的应用分发平台专为中国Linux用户设计&#xff0c;让软件管理变得前所未有的简单高效。无论您是刚接触Linux的新手&#xff0c;还是经验丰富的开发者&#xff0c;都能在这里找到满…

作者头像 李华
网站建设 2026/5/22 5:33:34

颠覆传统!这款QtQuick桌面壳让你重新定义桌面体验

颠覆传统&#xff01;这款QtQuick桌面壳让你重新定义桌面体验 【免费下载链接】quickshell Flexible toolkit for making desktop shells with QtQuick, targeting Wayland and X11 项目地址: https://gitcode.com/gh_mirrors/qu/quickshell 还在为传统桌面环境的局限性…

作者头像 李华