一、环境准备与依赖安装
在开始编写代码之前,必须先配置好Python运行环境。本方案基于Python 3.8及以上版本,主要利用PaddleOCR进行中文识别,利用pandas进行数据整理。请严格按照以下步骤执行,避免环境冲突。
1. 安装Python依赖库
打开终端(Windows下为CMD或PowerShell),执行以下命令安装核心库。这里推荐使用清华源加速下载:
```bash
pip install paddlepaddle paddleocr pandas pillow openpyxl pdf2image -i https://pypi.tuna.tsinghua.edu.cn/simple
```
2. 安装Poppler依赖(处理PDF必备)
如果档案中包含PDF文件,必须安装Poppler工具将PDF转换为图片。
- Windows用户:访问
https://github.com/oschwartz10612/poppler-windows/releases/ 下载最新版Release,解压后将 bin 文件夹路径(如 C:\poppler-xx\bin)添加到系统环境变量 Path 中。
- Linux用户:执行
sudo apt-get install poppler-utils。
- macOS用户:执行
brew install poppler。
二、目录结构设计
为了实现自动化处理,请在本地创建一个项目文件夹(例如 police_archive_tool),并严格按照以下结构建立子文件夹:
- input/:存放待处理的原始档案图片或PDF文件。
- output/:程序运行后,生成的Excel归档表将保存在此处。
- temp/:存放PDF转换后的临时图片,程序会自动清理。
三、核心功能实现逻辑
本方案将整个流程封装为四个核心模块:文件预处理、OCR识别、关键信息提取、数据导出。
1. PDF转图像处理
公安档案多为扫描版PDF,OCR引擎无法直接读取,需先转换为图像。利用 pdf2image 库可以实现高保真转换。
代码逻辑中需指定 poppler_path,这是Windows用户最容易报错的地方,必须指向刚才解压的bin目录。
2. OCR文字识别
使用百度开源的 PaddleOCR。它在中文识别率和速度上优于Tesseract。初始化时设置 use_angle_cls=True 可以自动旋转文字,适应扫描件倾斜的问题。
3. 关键信息提取(正则)

识别出的全文是杂乱的,我们需要利用正则表达式提取“身份证号”、“姓名”、“案件编号”等核心元数据。
- 身份证号正则:
[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]
- 案件号正则示例:
某公\(\w+\)\[\d{4}\]\d+号(需根据实际文书格式调整)
4. 数据导出与脱敏
提取后的数据存入 pandas DataFrame,最后导出为Excel。出于安全考虑,导出前应对身份证号进行中间位脱敏处理。
四、完整代码实现
将以下代码保存为 archive_processor.py,放在项目根目录下。代码已包含完整注释,无需修改即可运行。
```python
import os
import re
import shutil
import pandas as pd
from paddleocr import PaddleOCR
from pdf2image import convert_from_path
from PIL import Image
import logging
配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
================= 配置区域 =================
文件夹路径配置
INPUT_DIR = 'input'
OUTPUT_DIR = 'output'
TEMP_DIR = 'temp'
OUTPUT_EXCEL = 'archive_result.xlsx'
Windows用户请修改此处为你的poppler bin路径,Linux/Mac可设为None
POPPLER_PATH = r"C:\Program Files\poppler-23.08.0\Library\bin"
初始化OCR模型,第一次运行会自动下载模型文件
ocr = PaddleOCR(use_angle_cls=True, lang="ch", show_log=False)
================= 核心函数 =================
def ensure_dirs():
"""确保所需目录存在"""
for dir_path in [INPUT_DIR, OUTPUT_DIR, TEMP_DIR]:
if not os.path.exists(dir_path):
os.makedirs(dir_path)
def convert_pdf_to_images(pdf_path):
"""
将PDF转换为图片列表
:param pdf_path: PDF文件路径
:return: 图片路径列表
"""
try:
注意:Windows下必须指定poppler_path
pages = convert_from_path(pdf_path, poppler_path=POPPLER_PATH)
image_paths = []
pdf_name = os.path.splitext(os.path.basename(pdf_path))[0]
for i, page in enumerate(pages):
temp_img_path = os.path.join(TEMP_DIR, f"{pdf_name}_page_{i+1}.jpg")
page.save(temp_img_path, 'JPEG')
image_paths.append(temp_img_path)
return image_paths
except Exception as e:
logging.error(f"PDF转换失败: {pdf_path}, 错误: {e}")
return []
def extract_text_from_image(img_path):
"""
使用PaddleOCR识别图片文字
:param img_path: 图片路径
:return: 识别出的完整文本字符串
"""
try:
result = ocr.ocr(img_path, cls=True)
full_text = ""
if result and result[0]:
for line in result[0]:
text = line[1][0]
full_text += text + "\n"
return full_text
except Exception as e:
logging.error(f"OCR识别失败: {img_path}, 错误: {e}")
return ""
def extract_key_info(text, filename):
"""
利用正则从文本中提取关键信息
:param text: OCR识别的文本
:param filename: 原始文件名
:return: 字典格式的信息
"""
身份证号正则(支持18位)
id_card_pattern = r"[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]"
姓名提取(简单示例:匹配“姓名:”后的中文,需根据实际文书格式优化)
name_pattern = r"姓名[::]\s([\u4e00-\u9fa5]{2,4})"
案件号示例(需根据实际公安文书格式修改)
case_no_pattern = r"案件编号[::]\s([A-Za-z0-9\-]+)"
id_match = re.search(id_card_pattern, text)
name_match = re.search(name_pattern, text)
case_match = re.search(case_no_pattern, text)
info = {
"文件名": filename,
"姓名": name_match.group(1) if name_match else "未识别",
"身份证号": id_match.group(0) if id_match else "未识别",
"案件编号": case_match.group(1) if case_match else "未识别",
"OCR全文摘要": text[:50] + "..." 仅保留前50字作为摘要
}
return info
def mask_sensitive_data(df):
"""
对Excel中的身份证号进行脱敏处理
"""
def mask_id(id_str):
if len(id_str) == 18:
return id_str[:6] + "" + id_str[-4:]
return id_str
if "身份证号" in df.columns:
df["身份证号"] = df["身份证号"].apply(mask_id)
return df
def main():
ensure_dirs()
all_data = []
遍历输入文件夹
files = os.listdir(INPUT_DIR)
if not files:
logging.warning("input目录为空,请放入档案文件。")
return
for file in files:
file_path = os.path.join(INPUT_DIR, file)
logging.info(f"正在处理文件: {file}")
images_to_process = []
判断文件类型
if file.lower().endswith('.pdf'):
images_to_process = convert_pdf_to_images(file_path)
elif file.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp')):
images_to_process = [file_path]
else:
logging.warning(f"跳过不支持的文件格式: {file}")
continue
对每一页/每一张图进行识别
注意:如果一个文件有多页,通常取第一页或合并所有页文本。
这里我们取所有识别结果的汇总。
combined_text = ""
for img_path in images_to_process:
text = extract_text_from_image(img_path)
combined_text += text + "\n"
提取信息
if combined_text.strip():
file_info = extract_key_info(combined_text, file)
all_data.append(file_info)
清理临时图片
if file.lower().endswith('.pdf'):
for img in images_to_process:
if os.path.exists(img):
os.remove(img)
数据导出
if all_data:
df = pd.DataFrame(all_data)
df = mask_sensitive_data(df)
output_path = os.path.join(OUTPUT_DIR, OUTPUT_EXCEL)
df.to_excel(output_path, index=False)
logging.info(f"处理完成!结果已保存至: {output_path}")
else:
logging.info("未提取到任何有效信息。")
if __name__ == "__main__":
main()
```
五、常见问题处理
在实操过程中,可能会遇到以下技术细节问题,请对照排查:
1. 识别率低怎么办?
如果扫描件清晰度较差,可以在代码中加入图像预处理环节。在 extract_text_from_image 函数中,OCR识别前使用PIL对图片进行二值化和降噪处理:
```python
图像增强示例代码片段
from PIL import ImageEnhance
img = Image.open(img_path)
img = img.convert('L') 转灰度
img = ImageEnhance.Contrast(img).enhance(2.0) 提高对比度
img.save(img_path)
```
2. 提取不到特定字段?
公安文书种类繁多(拘留证、起诉意见书等),extract_key_info 函数中的正则表达式需要根据实际文书样式调整。建议先打印出 combined_text 查看OCR识别出的原始文本结构,再编写对应的正则。
3. 内存溢出?
如果批量处理几百个PDF,内存可能会爆。建议在 main 函数循环中,每处理10个文件就调用一次 import gc; gc.collect() 强制回收垃圾内存。