news 2026/4/16 0:24:46

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/4/15 16:16:28

Redhat7.4企业级Linux系统完整安装指南

Redhat7.4企业级Linux系统完整安装指南 【免费下载链接】Redhat7.4ISO官方镜像下载介绍 探索Redhat7.4的官方ISO镜像资源&#xff0c;这里为您提供了rhel-server-7.4-x86_64-dvd.iso的百度网盘永久下载链接。无论您是系统管理员还是开发者&#xff0c;都可以轻松获取这一稳定可…

作者头像 李华
网站建设 2026/4/15 16:16:29

Minecraft世界下载器终极指南:轻松保存服务器地图完整教程

Minecraft世界下载器终极指南&#xff1a;轻松保存服务器地图完整教程 【免费下载链接】minecraft-world-downloader Download Minecraft worlds, extend servers render distance. 1.12.2 - 1.20.1 项目地址: https://gitcode.com/gh_mirrors/mi/minecraft-world-downloader…

作者头像 李华
网站建设 2026/4/15 16:16:30

如何快速部署HunyuanVideo大视频模型:新手的完整实践指南

如何快速部署HunyuanVideo大视频模型&#xff1a;新手的完整实践指南 【免费下载链接】HunyuanVideo HunyuanVideo: A Systematic Framework For Large Video Generation Model 项目地址: https://gitcode.com/gh_mirrors/hu/HunyuanVideo 你是否曾经想过&#xff0c;仅…

作者头像 李华
网站建设 2026/4/15 16:16:29

电话号码安全输入:构建防恶意号码的前端防御体系

电话号码安全输入&#xff1a;构建防恶意号码的前端防御体系 【免费下载链接】intl-tel-input A JavaScript plugin for entering and validating international telephone numbers 项目地址: https://gitcode.com/gh_mirrors/in/intl-tel-input 在数字化业务快速发展的…

作者头像 李华
网站建设 2026/4/15 18:00:27

springboot_ssm微格教学视频标注系统

目录具体实现截图系统所用技术介绍写作提纲核心代码部分展示系统性能结论源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;具体实现截图 springboot_ssm微格教学视频标注系统 系统所用技术介绍 本系统采取了一系列的设计原则&…

作者头像 李华
网站建设 2026/4/15 18:01:21

Turing智能显示屏Python系统监控完整配置指南

Turing智能显示屏Python系统监控完整配置指南 【免费下载链接】turing-smart-screen-python Unofficial Python system monitor and library for small IPS USB-C displays like Turing Smart Screen or XuanFang 项目地址: https://gitcode.com/GitHub_Trending/tu/turing-s…

作者头像 李华