news 2026/2/24 19:51:26

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/2/14 0:00:32

如何快速解决iOS应用崩溃:KSCrash监控工具的完整指南

如何快速解决iOS应用崩溃&#xff1a;KSCrash监控工具的完整指南 【免费下载链接】KSCrash The Ultimate iOS Crash Reporter 项目地址: https://gitcode.com/gh_mirrors/ks/KSCrash 在iOS开发过程中&#xff0c;应用崩溃是开发者最头疼的问题之一。传统的崩溃日志往往信…

作者头像 李华
网站建设 2026/2/23 23:21:47

Google Model Viewer 完整指南:轻松构建网页3D模型和AR体验

Google Model Viewer 完整指南&#xff1a;轻松构建网页3D模型和AR体验 【免费下载链接】model-viewer Easily display interactive 3D models on the web and in AR! 项目地址: https://gitcode.com/gh_mirrors/mo/model-viewer 想要在网站上展示精美的3D模型吗&#…

作者头像 李华
网站建设 2026/2/18 15:59:58

xcaddy构建工具深度解析:Caddy插件编译的终极解决方案

xcaddy构建工具深度解析&#xff1a;Caddy插件编译的终极解决方案 【免费下载链接】xcaddy Build Caddy with plugins 项目地址: https://gitcode.com/gh_mirrors/xc/xcaddy xcaddy构建工具作为Caddy服务器生态中的核心组件&#xff0c;彻底解决了传统Caddy定制面临的复…

作者头像 李华
网站建设 2026/2/24 1:07:39

YOLO模型推理API按token收费,最低0.01元/次起

YOLO模型推理API按token收费&#xff0c;最低0.01元/次起 在智能制造车间的质检线上&#xff0c;一台工业相机每秒拍摄数十张产品图像&#xff0c;实时上传至云端——几毫秒后&#xff0c;系统便精准识别出某块电路板上的元件缺失&#xff0c;并自动触发停机警报。整个过程无需…

作者头像 李华
网站建设 2026/2/14 5:48:50

YOLO目标检测模型在无人机巡检中的应用实践

YOLO目标检测模型在无人机巡检中的应用实践 在电力线路跨越高山峡谷的日常运维中&#xff0c;一个微小的绝缘子裂纹可能在数月内演变为重大停电事故。传统依赖人工登塔检查的方式不仅效率低下&#xff0c;更伴随着高空作业的巨大风险。如今&#xff0c;随着搭载AI视觉系统的无人…

作者头像 李华