前言
在日常工作中,几乎所有职场人都会遇到一个高频痛点:非结构化内容的结构化提取。
HR 需要从几十上百份简历图片 / PDF 中,提取候选人的学历、工作经历、技能标签等信息;财务需要从发票、报销单截图中,提取金额、开票时间、税号等核心字段;商务需要从合同扫描件中,提取合作期限、金额、甲乙双方权责等关键信息;运营需要从数据报表截图中,提取核心指标并整理成可分析的表格。
传统的 OCR 工具只能提取纯文本,无法按照业务需求做结构化分类,手动整理录入不仅耗时耗力,还极易出现人为错误,几百份文件的处理往往需要耗费一整天的时间。而市面上的商用提取工具,不仅价格高昂,还无法自定义提取规则,难以适配个性化的业务场景。
本文就带大家从零开发一款开箱即用、高度自定义、全场景适配的 AI 结构化数据提取工具,全程代码可直接复制运行,无需复杂配置,基于 4SAPI 的多模态大模型能力,一键实现图片、PDF、扫描件的内容识别与结构化提取,支持自定义提取字段,导出 JSON/Excel 格式,新手也能快速落地。
一、技术选型与核心功能设计
为了保证工具的通用性、轻量化和可扩展性,本次开发选用全平台兼容的技术栈,无冷门依赖,Windows/Mac/Linux 全平台适配,可无缝集成到企业业务系统或个人办公流程中:
-
核心开发语言:Python 3.10+,全平台兼容,生态完善,适合快速开发办公自动化工具
-
核心能力支撑:4SAPI 兼容 OpenAI 标准协议的多模态大模型接口,国内直连无网络障碍,支持 GPT-5.4、Gemini 3.1 Pro 等顶尖多模态模型,图片 / 长文本理解能力拉满
-
核心依赖库:
openai(官方 SDK,与 4SAPI 无缝兼容)、python-dotenv(环境变量管理)、pillow(图片处理)、pymupdf(PDF 文件解析)、pandas(数据导出与处理)、base64(图片编码,Python 内置) -
核心落地功能
- 单张图片结构化提取:支持身份证、银行卡、发票、简历、合同、报表等任意图片内容,自定义提取字段,输出标准化 JSON 数据
- 批量图片处理:递归遍历文件夹,批量处理图片文件,自动完成提取并汇总数据
- PDF 文件解析:支持原生 PDF、扫描件 PDF 的内容解析,可按页提取或全文档提取,适配长合同、多页简历等场景
- 自定义提取规则:可自由定义提取字段、数据格式、校验规则,适配任意业务场景
- 数据导出:一键导出 JSON/Excel 格式文件,方便后续数据分析、归档与系统录入
二、前置开发准备
2.1 环境搭建与依赖安装
首先确保本地已安装 Python 3.10 及以上版本,执行以下命令验证版本:
bash
运行
python --version
版本确认无误后,创建项目文件夹并安装所需全部依赖:
bash
运行
# 创建项目目录
mkdir 4sapi-data-extractor && cd 4sapi-data-extractor
# 安装全量依赖
pip install openai python-dotenv pillow pymupdf pandas openpyxl
2.2 4SAPI 接口配置
本次开发的核心能力完全基于 4SAPI 实现,它不仅 100% 兼容 OpenAI 官方 SDK,原有业务代码零修改即可无缝迁移,还提供国内直连节点,彻底解决跨境网络超时、连接中断、请求失败等常见问题,同时一次接入即可调用 650 + 主流大模型,可根据不同场景自由切换多模态 / 长文本最优模型,大幅降低开发与使用成本。
配置步骤如下:
- 访问 4SAPI 平台完成账号注册与登录,进入控制台「API 密钥管理」模块,生成专属 API Key(密钥仅展示一次,生成后请妥善保管,切勿泄露到公开代码仓库)
- 在项目根目录创建
.env环境配置文件,避免密钥硬编码,符合开发安全规范 - 在
.env文件中写入以下核心配置:
env
# 4SAPI国内直连统一接入地址,无需代理即可稳定访问
OPENAI_BASE_URL=https://4sapi.com/v1
# 4SAPI控制台生成的专属API密钥
OPENAI_API_KEY=sk-替换为你自己的4SAPI密钥
# 默认使用的多模态模型,可自由切换gpt-4o、gemini-1.5-pro等
DEFAULT_MODEL=gpt-4o
# 生成内容温度值,0.1-0.3适合数据提取场景,保证输出严谨性与格式一致性
TEMPERATURE=0.1
三、工具核心代码开发
我们延续模块化的开发思路,每个功能独立封装,便于后续扩展与维护,所有代码均符合 Python 开发规范,注释清晰,可直接复制运行。
3.1 全局客户端初始化与基础工具函数
在项目根目录创建data_extractor.py核心入口文件,首先完成环境配置加载、4SAPI 客户端初始化与通用工具函数封装:
python
运行
import os
import re
import base64
import json
from pathlib import Path
from dotenv import load_dotenv
from openai import OpenAI
from PIL import Image
import fitz # pymupdf,用于PDF解析
import pandas as pd
# 加载.env环境配置
load_dotenv()
# 初始化4SAPI客户端,100%兼容OpenAI官方SDK,仅需2个配置项即可完成接入
client = OpenAI(
api_key=os.getenv("OPENAI_API_KEY"),
base_url=os.getenv("OPENAI_BASE_URL"),
)
# 全局常量配置
DEFAULT_MODEL = os.getenv("DEFAULT_MODEL", "gpt-4o")
TEMPERATURE = float(os.getenv("TEMPERATURE", 0.1))
# 支持的图片格式
SUPPORTED_IMAGE_FORMATS = [".jpg", ".jpeg", ".png", ".bmp", ".tiff", ".webp"]
# 支持的文档格式
SUPPORTED_DOC_FORMATS = [".pdf"]
# ------------------------------ 通用工具函数 ------------------------------
def image_to_base64(image_path: str) -> str:
"""
将图片文件转换为base64编码,适配4SAPI多模态接口输入规范
:param image_path: 图片文件路径
:return: base64编码后的图片字符串
"""
image_path = Path(image_path)
if not image_path.exists():
raise FileNotFoundError(f"图片文件不存在:{image_path}")
# 压缩图片,避免token超限,最大分辨率限制为2000px
with Image.open(image_path) as img:
max_size = 2000
if max(img.width, img.height) > max_size:
scale = max_size / max(img.width, img.height)
new_size = (int(img.width * scale), int(img.height * scale))
img = img.resize(new_size, Image.Resampling.LANCZOS)
# 转换为base64编码
buffer = io.BytesIO()
img.save(buffer, format="PNG")
base64_data = base64.b64encode(buffer.getvalue()).decode("utf-8")
return f"data:image/png;base64,{base64_data}"
def extract_text_from_pdf(pdf_path: str) -> str:
"""
从PDF文件中提取全量文本内容,适配原生PDF与可复制的扫描件PDF
:param pdf_path: PDF文件路径
:return: 提取后的全量文本内容
"""
pdf_path = Path(pdf_path)
if not pdf_path.exists():
raise FileNotFoundError(f"PDF文件不存在:{pdf_path}")
text_content = ""
with fitz.open(pdf_path) as doc:
for page_num, page in enumerate(doc, start=1):
page_text = page.get_text()
text_content += f"\n===== 第{page_num}页 =====\n{page_text}"
return text_content
def call_4sapi_llm(prompt: str, system_prompt: str, image_base64: str = None) -> str:
"""
统一封装4SAPI大模型调用函数,支持纯文本与多模态输入,所有功能模块复用
:param prompt: 用户具体请求内容
:param system_prompt: 系统提示词,定义模型角色与输出规范
:param image_base64: 图片base64编码,多模态场景传入
:return: 模型生成的文本内容
"""
try:
# 构建消息内容,支持纯文本与图片+文本混合输入
messages_content = [{"type": "text", "text": prompt}]
if image_base64:
messages_content.append({"type": "image_url", "image_url": {"url": image_base64}})
# 调用4SAPI接口,完全兼容OpenAI官方接口格式
response = client.chat.completions.create(
model=DEFAULT_MODEL,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": messages_content}
],
temperature=TEMPERATURE,
stream=False,
response_format={"type": "json_object"} # 强制输出JSON格式,保证结构化一致性
)
return response.choices[0].message.content.strip()
except Exception as e:
print(f"4SAPI接口调用失败:{str(e)}")
return ""
这里核心优势在于,4SAPI 完全兼容 OpenAI 的多模态接口规范与 JSON 模式输出,我们无需为多模态能力开发额外的适配代码,原有基于 OpenAI 开发的业务逻辑,仅需修改 base_url 和 api_key 两个参数,即可零成本迁移,大幅降低开发与维护成本。
3.2 核心数据提取功能封装
3.2.1 单张图片结构化数据提取
这是工具的核心基础功能,支持任意场景的图片内容提取,可完全自定义提取字段,强制输出 JSON 格式,保证数据一致性。
python
运行
def extract_data_from_image(image_path: str, extract_fields: dict) -> dict:
"""
从图片中提取指定字段的结构化数据
:param image_path: 图片文件路径
:param extract_fields: 提取字段配置,格式为{"字段名": "字段说明与提取要求"}
:return: 提取后的结构化数据字典
"""
try:
# 图片转base64编码
image_base64 = image_to_base64(image_path)
print(f"正在处理图片:{Path(image_path).name}")
# 构建系统提示词,严格定义输出规范,保证提取准确性
system_prompt = f"""
你是一位专业的数据提取工程师,擅长从图片中精准提取指定信息,并输出标准化JSON格式数据。
你的任务要求如下:
1. 严格按照用户指定的字段进行提取,不得遗漏必填字段,不得新增无关字段
2. 提取的信息必须完全来自图片内容,不得虚构、编造任何信息,无法识别的字段填null
3. 严格按照字段说明的要求进行提取,保证数据格式符合要求,比如日期格式为YYYY-MM-DD,金额保留2位小数
4. 必须输出标准的JSON格式数据,不得输出任何额外的解释、说明、markdown格式,确保可直接被JSON解析
5. 需要提取的字段配置:{json.dumps(extract_fields, ensure_ascii=False)}
"""
# 用户提示词
prompt = "请从提供的图片中,提取指定字段的结构化数据,严格按照要求输出JSON格式内容。"
# 调用4SAPI接口提取数据
result_json = call_4sapi_llm(prompt, system_prompt, image_base64)
if not result_json:
print(f"图片 {Path(image_path).name} 提取失败,接口无返回内容")
return {}
# 解析JSON结果
result_data = json.loads(result_json)
# 补充文件名信息,便于批量处理时溯源
result_data["source_file"] = Path(image_path).name
return result_data
except json.JSONDecodeError:
print(f"图片 {Path(image_path).name} 提取失败,输出内容非标准JSON格式")
return {}
except Exception as e:
print(f"图片 {Path(image_path).name} 处理失败:{str(e)}")
return {}
3.2.2 PDF 文件结构化数据提取
针对长文档、多页合同、简历等 PDF 文件,封装专用的提取函数,支持全文档内容解析与自定义字段提取:
python
运行
def extract_data_from_pdf(pdf_path: str, extract_fields: dict) -> dict:
"""
从PDF文件中提取指定字段的结构化数据
:param pdf_path: PDF文件路径
:param extract_fields: 提取字段配置,格式为{"字段名": "字段说明与提取要求"}
:return: 提取后的结构化数据字典
"""
try:
# 提取PDF文本内容
pdf_text = extract_text_from_pdf(pdf_path)
print(f"正在处理PDF文件:{Path(pdf_path).name}")
# 构建系统提示词
system_prompt = f"""
你是一位专业的文档数据提取工程师,擅长从长文档中精准提取指定信息,并输出标准化JSON格式数据。
你的任务要求如下:
1. 严格按照用户指定的字段进行提取,不得遗漏必填字段,不得新增无关字段
2. 提取的信息必须完全来自提供的文档内容,不得虚构、编造任何信息,无法找到的字段填null
3. 严格按照字段说明的要求进行提取,保证数据格式符合要求,比如日期格式为YYYY-MM-DD,金额保留2位小数
4. 必须输出标准的JSON格式数据,不得输出任何额外的解释、说明、markdown格式,确保可直接被JSON解析
5. 需要提取的字段配置:{json.dumps(extract_fields, ensure_ascii=False)}
"""
# 用户提示词,传入文档全量内容
prompt = f"请从以下文档内容中,提取指定字段的结构化数据,严格按照要求输出JSON格式内容。文档内容:\n{pdf_text}"
# 调用4SAPI接口提取数据
result_json = call_4sapi_llm(prompt, system_prompt)
if not result_json:
print(f"PDF文件 {Path(pdf_path).name} 提取失败,接口无返回内容")
return {}
# 解析JSON结果
result_data = json.loads(result_json)
result_data["source_file"] = Path(pdf_path).name
return result_data
except json.JSONDecodeError:
print(f"PDF文件 {Path(pdf_path).name} 提取失败,输出内容非标准JSON格式")
return {}
except Exception as e:
print(f"PDF文件 {Path(pdf_path).name} 处理失败:{str(e)}")
return {}
3.3 批量处理与数据导出功能
针对批量文件处理的高频需求,封装批量遍历函数,同时支持提取结果一键导出 JSON/Excel 格式,满足办公归档与数据录入需求:
python
运行
def batch_extract_data(dir_path: str, extract_fields: dict) -> list:
"""
批量遍历文件夹,处理所有支持的图片与PDF文件,提取结构化数据
:param dir_path: 目标文件夹路径
:param extract_fields: 提取字段配置
:return: 所有文件的提取结果列表
"""
dir_path = Path(dir_path)
if not dir_path.is_dir():
print(f"错误:目标文件夹 {dir_path} 不存在")
return []
all_result = []
# 遍历所有支持的文件
for file_path in dir_path.iterdir():
if file_path.is_file():
file_suffix = file_path.suffix.lower()
if file_suffix in SUPPORTED_IMAGE_FORMATS:
# 处理图片文件
result = extract_data_from_image(str(file_path), extract_fields)
if result:
all_result.append(result)
elif file_suffix in SUPPORTED_DOC_FORMATS:
# 处理PDF文件
result = extract_data_from_pdf(str(file_path), extract_fields)
if result:
all_result.append(result)
print(f"批量处理完成,共处理文件{len(all_result)}个")
return all_result
def export_data_to_file(data_list: list, output_path: str, format: str = "excel"):
"""
将提取结果导出到文件,支持Excel和JSON格式
:param data_list: 提取结果列表
:param output_path: 输出文件路径
:param format: 导出格式,支持excel/json
"""
if not data_list:
print("无数据可导出")
return
output_path = Path(output_path)
try:
if format.lower() == "json":
# 导出JSON格式
with open(output_path, "w", encoding="utf-8") as f:
json.dump(data_list, f, ensure_ascii=False, indent=4)
print(f"数据已成功导出至JSON文件:{output_path}")
elif format.lower() == "excel":
# 导出Excel格式
df = pd.DataFrame(data_list)
df.to_excel(output_path, index=False, engine="openpyxl")
print(f"数据已成功导出至Excel文件:{output_path}")
else:
print(f"不支持的导出格式:{format}")
except Exception as e:
print(f"数据导出失败:{str(e)}")
3.4 工具入口封装
最后,我们封装一个简单的调用入口,用户只需配置提取字段,即可一键完成处理,无需修改核心代码:
python
运行
if __name__ == "__main__":
# ------------------------------ 自定义配置区 ------------------------------
# 1. 定义需要提取的字段,可根据业务场景自由修改
# 示例1:简历信息提取配置
EXTRACT_FIELDS = {
"姓名": "候选人的完整姓名",
"年龄": "候选人的年龄,数字格式",
"联系电话": "候选人的手机号码",
"邮箱": "候选人的电子邮箱地址",
"最高学历": "候选人的最高学历,如本科、硕士、博士",
"毕业院校": "候选人最高学历对应的毕业院校",
"工作年限": "候选人的总工作年限,数字格式",
"最近一份工作的公司名称": "候选人最近一份工作的任职公司全称",
"最近一份工作的任职岗位": "候选人最近一份工作的任职岗位",
"核心技能标签": "候选人的核心专业技能,数组格式"
}
# 示例2:发票信息提取配置(可替换上面的配置使用)
# EXTRACT_FIELDS = {
# "发票类型": "增值税专用发票/普通发票",
# "发票代码": "发票左上角的12位发票代码",
# "发票号码": "发票右上角的8位发票号码",
# "开票日期": "发票的开票日期,格式YYYY-MM-DD",
# "购买方名称": "购买方单位全称",
# "购买方纳税人识别号": "购买方的纳税人识别号",
# "合计金额": "发票不含税合计金额,保留2位小数,数字格式",
# "合计税额": "发票合计税额,保留2位小数,数字格式",
# "价税合计": "发票价税合计总金额,保留2位小数,数字格式",
# "销售方名称": "销售方单位全称",
# "销售方纳税人识别号": "销售方的纳税人识别号"
# }
# 2. 配置处理目标,支持单文件/文件夹批量处理
# 单文件处理
# TARGET_PATH = "./简历.pdf"
# 批量文件夹处理
TARGET_PATH = "./简历文件夹"
# 3. 配置输出文件路径
OUTPUT_EXCEL_PATH = "./提取结果_简历信息.xlsx"
OUTPUT_JSON_PATH = "./提取结果_简历信息.json"
# -------------------------------------------------------------------------
# 执行处理逻辑
target_path = Path(TARGET_PATH)
if target_path.is_file():
# 单文件处理
file_suffix = target_path.suffix.lower()
if file_suffix in SUPPORTED_IMAGE_FORMATS:
result = extract_data_from_image(str(target_path), EXTRACT_FIELDS)
result_list = [result] if result else []
elif file_suffix in SUPPORTED_DOC_FORMATS:
result = extract_data_from_pdf(str(target_path), EXTRACT_FIELDS)
result_list = [result] if result else []
else:
print(f"不支持的文件格式:{file_suffix}")
result_list = []
elif target_path.is_dir():
# 批量文件夹处理
result_list = batch_extract_data(str(target_path), EXTRACT_FIELDS)
else:
print(f"目标路径不存在:{TARGET_PATH}")
result_list = []
# 导出结果
if result_list:
export_data_to_file(result_list, OUTPUT_EXCEL_PATH, format="excel")
export_data_to_file(result_list, OUTPUT_JSON_PATH, format="json")
四、工具使用与效果演示
4.1 基础使用步骤
- 完成
.env文件配置,填入自己的 4SAPI 密钥,确保配置正确无误 - 在
data_extractor.py文件的__main__自定义配置区,修改EXTRACT_FIELDS提取字段配置,适配自己的业务场景 - 配置
TARGET_PATH处理目标,支持单文件或文件夹批量处理 - 执行脚本,即可自动完成数据提取,并导出 Excel/JSON 结果文件:
bash
运行
python data_extractor.py
4.2 实际效果演示
以一份简历 PDF 文件为例,我们配置了简历信息提取字段,工具提取后的 JSON 结果如下:
json
{
"姓名": "张三",
"年龄": "28",
"联系电话": "138XXXX1234",
"邮箱": "zhangsan@example.com",
"最高学历": "硕士",
"毕业院校": "XX大学",
"工作年限": "5",
"最近一份工作的公司名称": "XX科技有限公司",
"最近一份工作的任职岗位": "Python后端开发工程师",
"核心技能标签": ["Python", "FastAPI", "MySQL", "Redis", "Docker", "微服务"],
"source_file": "张三_后端开发工程师.pdf"
}
提取完成后,工具会自动将所有结果汇总,导出为 Excel 表格,可直接用于 HR 人才库录入、筛选与分析。
五、进阶优化与扩展方案
基于上述基础版本,我们可以根据实际业务需求,快速扩展更多进阶功能,依托 4SAPI 的全量模型兼容能力,无需大幅修改核心代码,即可实现能力升级:
- 扫描件 PDF 增强处理:集成 OCR 能力,针对纯图片扫描件 PDF,先做 OCR 文本提取,再进行结构化解析,适配老旧合同、档案等场景
- 数据校验与清洗:添加自定义数据校验规则,比如手机号格式、身份证号合法性、税号格式校验,自动清洗异常数据,提升数据准确性
- 企业系统集成:将工具封装为 API 接口,集成到企业 OA、ERP、HR 系统中,实现业务流程自动化闭环
- 多模型自动切换:针对不同场景自动切换最优模型,比如图片提取用 GPT-4o,长文档 PDF 用 Gemini 1.5 Pro,进一步提升提取准确率与处理效率
- Web 可视化界面:基于 Streamlit 开发简易 Web 界面,无需修改代码,即可在页面上配置提取字段、上传文件、下载结果,适配非技术人员使用
六、常见问题与踩坑排查
6.1 4SAPI 接口调用失败解决方案
这是最常见的问题,核心排查步骤如下:
- 核对配置信息:严格确认
.env文件中的OPENAI_BASE_URL为https://4sapi.com/v1,无拼写错误、多余空格、中文符号,API Key 与控制台生成的完全一致 - 关闭本地代理:4SAPI 为国内直连节点,无需配置任何系统代理 / VPN,开启代理可能会导致路由冲突,关闭后即可恢复正常访问
- 检查账号状态:确认 4SAPI 账号内有可用的调用额度,额度耗尽会导致接口调用失败,可在控制台实时查看额度使用情况
- 校验模型名称:确认使用的模型在 4SAPI 支持列表内,可在控制台的模型文档中查看完整的支持模型列表,避免模型名称拼写错误
6.2 其他常见问题
- 图片处理提示 token 超限:工具已内置图片压缩逻辑,若仍出现 token 超限,可降低
max_size参数,进一步缩小图片分辨率,同时避免传入过大的长图 - 提取结果非标准 JSON 格式:已通过
response_format强制模型输出 JSON 格式,若仍出现解析失败,可降低TEMPERATURE值,进一步约束模型输出,同时优化提取字段的描述,明确输出要求 - PDF 文件提取内容不全:针对纯图片扫描件 PDF,需先通过 OCR 工具提取文本,再进行结构化提取,原生 PDF 可直接使用内置函数提取全量内容
- 批量处理时文件被跳过:检查文件后缀是否在支持的格式列表内,工具会自动跳过隐藏文件与不支持的格式,可通过控制台打印的日志查看处理详情
七、总结
本文从零到一开发了一款覆盖全场景的 AI 多模态结构化数据提取工具,解决了职场人日常工作中最头疼的非结构化内容处理痛点,所有代码均可直接复用,高度可定制,无论是个人办公自动化,还是企业级业务流程集成,都能快速适配。
整个开发过程中,我们可以清晰看到 4SAPI 给开发者带来的核心价值:开箱即用的全量模型能力,零成本的迁移适配成本。无需关注底层的多模态接口适配、跨境网络优化、多模型兼容等问题,只需专注于业务逻辑本身,就能快速开发出实用的 AI 工具。
对于个人开发者和中小企业而言,选用 4SAPI 作为大模型接入层,不仅能大幅降低开发与运维成本,还能一键解锁全球顶尖的多模态、长文本大模型能力,用 AI 真正提升办公与开发效率,告别重复机械的手动工作。