拉萨市网站建设_网站建设公司_移动端适配_seo优化
2026/1/5 12:00:11 网站建设 项目流程

在日常工作中,我们经常会遇到大量图片格式的PDF文件(如扫描件、截图生成的PDF),这类文件无法直接复制文本,手动逐页OCR识别效率极低。本文将介绍一套基于Python+Dify的全自动化解决方案,实现从PDF批量转图片、图片上传OCR识别到文本合并的完整流程,适用于文档数字化、数据提取等场景。

一、方案整体架构

本方案围绕"批量处理、自动化执行、精准识别"三大核心需求设计,整体架构分为4个关键环节,全程无需人工干预:

graph TDA[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算法:

  1. 登录Dify平台(https://dify.ai/),创建「工作流」
  2. 添加「图片上传」输入节点,字段名设为photo(类型选择「图片」,允许PNG格式)
  3. 集成OCR识别节点(支持内置OCR或第三方工具如阿里云OCR、百度OCR、谷歌LLM模型)
  4. 配置输出节点,将识别结果映射为text字段
  5. 发布工作流,获取「工作流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未找到

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识别结果为空或乱码

4. 批量处理速度慢

  • 解决方案:
    • 增加thread_count参数(如CPU为8核可设为6-7)
    • 优化Dify工作流响应模式(使用blocking同步模式确保顺序)
    • 对超大PDF文件可分批次处理,避免内存占用过高

五、方案优势与扩展方向

方案优势

  1. 全自动化:从PDF读取到文本生成全程无需人工干预,支持批量处理
  2. 顺序保障:严格保持原PDF页码顺序,文本合并时添加分页标识,便于核对
  3. 高兼容性:支持Windows/Mac/Linux跨平台运行,适配不同格式的图片PDF
  4. 健壮性强:包含重试机制、异常捕获、已处理文件跳过等功能,稳定性高
  5. 低代码门槛:借助Dify平台快速配置OCR工作流,无需手动开发复杂识别算法

扩展方向

  1. 支持加密PDF:集成PyPDF2库解析加密PDF文件
  2. 文本格式优化:添加多余空行去除、表格结构还原等后处理逻辑
  3. 多线程并发:使用concurrent.futures实现多PDF并行处理,提升效率
  4. 结果校验:集成人工审核环节,标记识别失败或模糊的页面
  5. 云原生部署:打包为Docker镜像,部署到云服务器或K8s集群,支持定时任务

六、总结

本文提出的基于Python+Dify的批量OCR解决方案,完美解决了图片PDF的文本提取难题。通过将PDF转图片、Dify OCR识别、文本合并等环节自动化串联,大幅提升了文档处理效率,适用于企业办公、教育培训、政务处理等多个场景。

该方案兼顾了易用性和扩展性,既可以直接部署使用,也可以根据实际需求进行二次开发。随着AI识别技术的不断进步,结合Dify平台的灵活配置能力,后续还可以进一步优化识别精度和处理效率,为文档数字化转型提供更强大的支持。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询