当前位置: 代码网 > it编程>前端脚本>Python > 基于Python+Dify实现批量OCR识别的自动化解决方案

基于Python+Dify实现批量OCR识别的自动化解决方案

2025年12月04日 Python 我要评论
在日常工作中,我们经常会遇到大量图片格式的pdf文件(如扫描件、截图生成的pdf),这类文件无法直接复制文本,手动逐页ocr识别效率极低。本文将介绍一套基于python+dify的全自动化解决方案,实

在日常工作中,我们经常会遇到大量图片格式的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转图片核心依赖)

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识别的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com