在日常工作中,我们经常会遇到大量图片格式的pdf文件(如扫描件、截图生成的pdf),这类文件无法直接复制文本,手动逐页ocr识别效率极低。本文将介绍一套基于python+dify的全自动化解决方案,实现从pdf批量转图片、图片上传ocr识别到文本合并的完整流程,适用于文档数字化、数据提取等场景。
一、方案整体架构
本方案围绕"批量处理、自动化执行、精准识别"三大核心需求设计,整体架构分为4个关键环节,全程无需人工干预:
graph td
a[pdf文件目录] --> b[python批量读取pdf]
b --> c[pdf转png图片(按页拆分)]
c --> d[图片上传dify平台]
d --> e[dify ocr工作流识别文本]
e --> f[按pdf原顺序合并文本]
f --> g[生成同名结构化文本文件]
核心技术栈
- 后端语言:python 3.8+(跨平台兼容,生态丰富)
- pdf转图片:pdf2image(封装poppler引擎,转换精度高)
- 图像处理:pillow(图片格式标准化)
- api调用:requests(与dify平台交互)
- ocr识别:dify工作流(可视化配置,支持第三方ocr工具集成)
二、前置准备工作
在开始实现前,需完成环境配置和平台准备,确保全流程顺畅运行。
1. 开发环境配置
(1)python依赖安装
# 核心依赖库 pip install pdf2image pillow requests glob3 pathlib
(2)poppler引擎安装(pdf转图片核心依赖)
- windows:下载二进制包(https://github.com/oschwartz10612/poppler-wheels/releases),解压后将
bin目录添加到系统环境变量 - mac:通过homebrew安装
brew install poppler - linux(ubuntu/debian):
sudo apt-get install poppler-utils
2. dify平台配置
dify作为低代码平台,提供了便捷的工作流配置能力,无需手动开发ocr算法:
- 登录dify平台(https://dify.ai/),创建「工作流」
- 添加「图片上传」输入节点,字段名设为
photo(类型选择「图片」,允许png格式) - 集成ocr识别节点(支持内置ocr或第三方工具如阿里云ocr、百度ocr、谷歌llm模型)
- 配置输出节点,将识别结果映射为
text字段 - 发布工作流,获取「工作流id」和「api密钥」(个人设置→api密钥)
三、核心功能实现
下面按流程拆解核心功能代码,每个模块均提供完整实现和关键注释。
1. 工具函数:批量读取pdf文件
实现指定目录下所有pdf文件的自动扫描和排序,确保处理顺序可预期:
import glob
import os
from typing import list
def get_all_pdf_in_dir(pdf_dir: str) -> list[str]:
"""
获取指定目录下所有pdf文件的绝对路径(按文件名排序)
"""
if not os.path.exists(pdf_dir):
raise filenotfounderror(f"pdf目录不存在:{pdf_dir}")
# 匹配所有.pdf文件(不区分大小写)
pdf_pattern = os.path.join(pdf_dir, "*.pdf")
pdf_files = glob.glob(pdf_pattern, recursive=false)
# 按文件名排序,确保处理顺序一致
pdf_files.sort()
if not pdf_files:
print(f"警告:目录 {pdf_dir} 中未找到pdf文件")
return []
print(f"成功找到 {len(pdf_files)} 个pdf文件:")
for idx, pdf_file in enumerate(pdf_files, start=1):
print(f" {idx}. {os.path.basename(pdf_file)}")
return pdf_files
2. pdf转png:按页拆分并独立存储
为每个pdf创建独立目录存储图片,避免文件混淆,同时保证页码顺序:
from pdf2image import convert_from_path
from pathlib import path
def pdf_to_png(
pdf_path: str,
root_image_dir: str = "pdf_images",
dpi: int = 300,
fmt: str = "png"
) -> list[str]:
"""
pdf按页转png,每个pdf生成独立目录,返回图片路径列表(按页码排序)
"""
pdf_filename = os.path.splitext(os.path.basename(pdf_path))[0]
pdf_image_dir = os.path.join(root_image_dir, pdf_filename)
# 创建独立目录(支持多级目录自动创建)
path(pdf_image_dir).mkdir(parents=true, exist_ok=true)
print(f" 图片输出目录:{os.path.abspath(pdf_image_dir)}")
# mac/linux可自动识别poppler,windows需指定路径
poppler_path = "/opt/homebrew/cellar/poppler/25.12.0/bin" if os.name != "nt" else none
if os.name == "nt" and not poppler_path:
raise valueerror("windows系统需指定poppler的bin目录路径")
try:
# 按页转换pdf为图片(保持原顺序)
images = convert_from_path(
pdf_path=pdf_path,
dpi=dpi, # 分辨率越高识别越准,建议≥200
thread_count=4, # 多线程提速
fmt=fmt,
grayscale=false,
poppler_path=poppler_path
)
image_paths = []
for page_num, image in enumerate(images, start=1):
output_filename = f"{pdf_filename}_page_{page_num:02d}.{fmt}"
output_path = os.path.join(pdf_image_dir, output_filename)
image.save(output_path, fmt.upper())
image_paths.append(output_path)
print(f" pdf转png完成:共生成 {len(image_paths)} 张图片")
return image_paths
except exception as e:
print(f" pdf转png失败:{str(e)}")
raise
3. dify交互:图片上传与ocr工作流调用
基于dify api实现图片上传和工作流调用,处理网络异常和重试逻辑:
import requests
import time
from typing import optional
# dify全局配置(需替换为实际信息)
dify_api_key = "app-xxxxxxxx"
dify_api_base_url = "https://api.dify.ai/v1"
dify_user = "difyuser"
retry_times = 3
retry_delay = 2
def upload_image_to_dify(image_path: str) -> optional[str]:
"""上传图片到dify,返回文件id"""
upload_url = f"{dify_api_base_url}/files/upload"
headers = {"authorization": f"bearer {dify_api_key}"}
try:
with open(image_path, 'rb') as file:
files = {'file': (os.path.basename(image_path), file, 'image/png')}
data = {"user": dify_user, "type": "image"}
response = requests.post(upload_url, headers=headers, files=files, data=data)
if response.status_code == 201:
file_id = response.json().get("id")
print(f" 图片上传成功,file_id:{file_id[:10]}...")
return file_id
else:
print(f" 图片上传失败,状态码:{response.status_code},响应:{response.text}")
return none
except exception as e:
print(f" 图片上传异常:{str(e)}")
return none
def run_ocr_workflow(file_id: str) -> optional[str]:
"""调用dify ocr工作流,返回识别文本"""
workflow_url = f"{dify_api_base_url}/workflows/run"
headers = {
"authorization": f"bearer {dify_api_key}",
"content-type": "application/json"
}
data = {
"inputs": {
"photo": {
"transfer_method": "local_file",
"upload_file_id": file_id,
"type": "image"
}
},
"response_mode": "blocking",
"user": dify_user
}
try:
response = requests.post(workflow_url, headers=headers, json=data)
if response.status_code == 200:
result = response.json()
# 解析dify响应结构(data→outputs→text)
if "data" in result and result["data"]["status"] == "succeeded":
outputs = result["data"].get("outputs", {})
ocr_text = outputs.get("text", "").strip()
if ocr_text:
print(f" ocr识别成功,文本长度:{len(ocr_text)}字")
return ocr_text
print(f" ocr结果解析失败:{result}")
return none
else:
print(f" 工作流调用失败,状态码:{response.status_code},响应:{response.text}")
return none
except exception as e:
print(f" 工作流调用异常:{str(e)}")
return none
4. 文本合并:按原顺序生成结构化文件
将每页ocr结果按pdf原页码顺序合并,生成与原pdf同名的文本文件:
def batch_ocr_and_merge(
image_paths: list[str],
pdf_path: str,
output_dir: str = "ocr_results",
output_suffix: str = "txt"
) -> none:
"""批量ocr识别并按页码顺序合并文本"""
total_images = len(image_paths)
merged_text = []
# 创建文本输出目录
path(output_dir).mkdir(parents=true, exist_ok=true)
pdf_filename = os.path.splitext(os.path.basename(pdf_path))[0]
output_text_path = os.path.join(output_dir, f"{pdf_filename}.{output_suffix}")
# 跳过已处理文件,避免重复劳动
if os.path.exists(output_text_path):
print(f" 跳过已处理文件:{os.path.basename(output_text_path)}")
return
print(f" 开始ocr处理(共{total_images}张图片)...")
for idx, image_path in enumerate(image_paths, start=1):
print(f"\n 处理第{idx}/{total_images}张:{os.path.basename(image_path)}")
# 图片上传(带重试机制)
file_id = none
for retry in range(retry_times):
file_id = upload_image_to_dify(image_path)
if file_id:
break
print(f" 第{retry+1}次上传重试...")
time.sleep(retry_delay)
if not file_id:
merged_text.extend([f"===== 第{idx}页(图片上传失败) =====", "\n"])
continue
# ocr识别(带重试机制)
ocr_text = none
for retry in range(retry_times):
ocr_text = run_ocr_workflow(file_id)
if ocr_text:
break
print(f" 第{retry+1}次ocr重试...")
time.sleep(retry_delay)
if ocr_text:
merged_text.extend([f"===== 第{idx}页 =====", ocr_text, "\n"])
else:
merged_text.extend([f"===== 第{idx}页(ocr识别失败) =====", "\n"])
# 保存合并文本(utf-8编码避免中文乱码)
final_text = "\n".join(merged_text)
with open(output_text_path, "w", encoding="utf-8") as f:
f.write(final_text)
print(f"\n 文本合并完成!保存路径:{os.path.abspath(output_text_path)}")
print(f" 合并后总文本长度:{len(final_text)}字")
5. 主函数:串联全流程执行
def main():
# 配置参数(可根据实际需求调整)
pdf_dir = "./pdf_files" # pdf文件存放目录
root_image_dir = "pdf_images" # 图片存储根目录
ocr_output_dir = "ocr_results" # 文本输出目录
output_suffix = "txt" # 输出文件后缀(支持txt/md)
pdf_dpi = 300 # 图片分辨率(建议200-300dpi)
try:
# 步骤1:获取所有pdf文件
pdf_files = get_all_pdf_in_dir(pdf_dir)
if not pdf_files:
return
# 步骤2:批量处理每个pdf
total_pdfs = len(pdf_files)
for pdf_idx, pdf_path in enumerate(pdf_files, start=1):
print(f"\n=== 处理第{pdf_idx}/{total_pdfs}个pdf:{os.path.basename(pdf_path)} ===")
try:
# 子步骤1:pdf转png
image_paths = pdf_to_png(pdf_path, root_image_dir, pdf_dpi)
# 子步骤2:ocr识别+文本合并
batch_ocr_and_merge(image_paths, pdf_path, ocr_output_dir, output_suffix)
print(f"=== 第{pdf_idx}/{total_pdfs}个pdf处理完成! ===\n" + "-"*50)
except exception as e:
print(f"=== 第{pdf_idx}/{total_pdfs}个pdf处理失败:{str(e)} ===\n" + "-"*50)
continue
print(f"\n所有pdf文件处理完毕!")
print(f"📁 图片文件存放于:{os.path.abspath(root_image_dir)}")
print(f"📄 ocr文本文件存放于:{os.path.abspath(ocr_output_dir)}")
except exception as e:
print(f"\n=== 批量处理流程异常终止:{str(e)} ===")
if __name__ == "__main__":
main()
四、关键问题解决方案
在实际部署和运行过程中,可能会遇到各类问题,以下是常见问题的解决方案:
1. pdf转png失败:poppler未找到
问题原因:系统未识别到poppler引擎
解决方案:
- windows:手动指定poppler路径,在
pdf_to_png函数中添加poppler_path=r"c:\poppler\bin" - mac/linux:重新安装poppler,确保环境变量配置正确
2. dify api调用400错误
错误类型1:photo in input form must be a file
解决方案:确保run_ocr_workflow函数中photo字段是对象格式(而非列表),即"photo": {}而非"photo": [{}]
错误类型2:detected file type does not match
解决方案:上传图片时mime类型设为image/png,dify工作流输入字段类型设为「图片」,参数type统一为image
3. ocr识别结果为空或乱码
解决方案:
- 提高pdf转图片的dpi(建议300dpi),确保图片清晰度
- 检查dify工作流中ocr节点配置,选择支持中文识别的模型
- 合并文本时使用utf-8编码,避免中文乱码
4. 批量处理速度慢
解决方案:
- 增加
thread_count参数(如cpu为8核可设为6-7) - 优化dify工作流响应模式(使用
blocking同步模式确保顺序) - 对超大pdf文件可分批次处理,避免内存占用过高
五、方案优势与扩展方向
方案优势
- 全自动化:从pdf读取到文本生成全程无需人工干预,支持批量处理
- 顺序保障:严格保持原pdf页码顺序,文本合并时添加分页标识,便于核对
- 高兼容性:支持windows/mac/linux跨平台运行,适配不同格式的图片pdf
- 健壮性强:包含重试机制、异常捕获、已处理文件跳过等功能,稳定性高
- 低代码门槛:借助dify平台快速配置ocr工作流,无需手动开发复杂识别算法
扩展方向
- 支持加密pdf:集成
pypdf2库解析加密pdf文件 - 文本格式优化:添加多余空行去除、表格结构还原等后处理逻辑
- 多线程并发:使用
concurrent.futures实现多pdf并行处理,提升效率 - 结果校验:集成人工审核环节,标记识别失败或模糊的页面
- 云原生部署:打包为docker镜像,部署到云服务器或k8s集群,支持定时任务
六、总结
本文提出的基于python+dify的批量ocr解决方案,完美解决了图片pdf的文本提取难题。通过将pdf转图片、dify ocr识别、文本合并等环节自动化串联,大幅提升了文档处理效率,适用于企业办公、教育培训、政务处理等多个场景。
该方案兼顾了易用性和扩展性,既可以直接部署使用,也可以根据实际需求进行二次开发。随着ai识别技术的不断进步,结合dify平台的灵活配置能力,后续还可以进一步优化识别精度和处理效率,为文档数字化转型提供更强大的支持。
以上就是基于python+dify实现批量ocr识别的自动化解决方案的详细内容,更多关于python ocr识别的资料请关注代码网其它相关文章!
发表评论