基于 4SAPI 开发 AI 多模态结构化数据提取工具:一键解析图片 / PDF / 文档核心信息

4 阅读19分钟

前言

在日常工作中,几乎所有职场人都会遇到一个高频痛点:非结构化内容的结构化提取

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 内置)

  • 核心落地功能

    1. 单张图片结构化提取:支持身份证、银行卡、发票、简历、合同、报表等任意图片内容,自定义提取字段,输出标准化 JSON 数据
    2. 批量图片处理:递归遍历文件夹,批量处理图片文件,自动完成提取并汇总数据
    3. PDF 文件解析:支持原生 PDF、扫描件 PDF 的内容解析,可按页提取或全文档提取,适配长合同、多页简历等场景
    4. 自定义提取规则:可自由定义提取字段、数据格式、校验规则,适配任意业务场景
    5. 数据导出:一键导出 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 + 主流大模型,可根据不同场景自由切换多模态 / 长文本最优模型,大幅降低开发与使用成本。

配置步骤如下:

  1. 访问 4SAPI 平台完成账号注册与登录,进入控制台「API 密钥管理」模块,生成专属 API Key(密钥仅展示一次,生成后请妥善保管,切勿泄露到公开代码仓库)
  2. 在项目根目录创建.env环境配置文件,避免密钥硬编码,符合开发安全规范
  3. .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 基础使用步骤

  1. 完成.env文件配置,填入自己的 4SAPI 密钥,确保配置正确无误
  2. data_extractor.py文件的__main__自定义配置区,修改EXTRACT_FIELDS提取字段配置,适配自己的业务场景
  3. 配置TARGET_PATH处理目标,支持单文件或文件夹批量处理
  4. 执行脚本,即可自动完成数据提取,并导出 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 的全量模型兼容能力,无需大幅修改核心代码,即可实现能力升级:

  1. 扫描件 PDF 增强处理:集成 OCR 能力,针对纯图片扫描件 PDF,先做 OCR 文本提取,再进行结构化解析,适配老旧合同、档案等场景
  2. 数据校验与清洗:添加自定义数据校验规则,比如手机号格式、身份证号合法性、税号格式校验,自动清洗异常数据,提升数据准确性
  3. 企业系统集成:将工具封装为 API 接口,集成到企业 OA、ERP、HR 系统中,实现业务流程自动化闭环
  4. 多模型自动切换:针对不同场景自动切换最优模型,比如图片提取用 GPT-4o,长文档 PDF 用 Gemini 1.5 Pro,进一步提升提取准确率与处理效率
  5. Web 可视化界面:基于 Streamlit 开发简易 Web 界面,无需修改代码,即可在页面上配置提取字段、上传文件、下载结果,适配非技术人员使用

六、常见问题与踩坑排查

6.1 4SAPI 接口调用失败解决方案

这是最常见的问题,核心排查步骤如下:

  1. 核对配置信息:严格确认.env文件中的OPENAI_BASE_URLhttps://4sapi.com/v1,无拼写错误、多余空格、中文符号,API Key 与控制台生成的完全一致
  2. 关闭本地代理:4SAPI 为国内直连节点,无需配置任何系统代理 / VPN,开启代理可能会导致路由冲突,关闭后即可恢复正常访问
  3. 检查账号状态:确认 4SAPI 账号内有可用的调用额度,额度耗尽会导致接口调用失败,可在控制台实时查看额度使用情况
  4. 校验模型名称:确认使用的模型在 4SAPI 支持列表内,可在控制台的模型文档中查看完整的支持模型列表,避免模型名称拼写错误

6.2 其他常见问题

  1. 图片处理提示 token 超限:工具已内置图片压缩逻辑,若仍出现 token 超限,可降低max_size参数,进一步缩小图片分辨率,同时避免传入过大的长图
  2. 提取结果非标准 JSON 格式:已通过response_format强制模型输出 JSON 格式,若仍出现解析失败,可降低TEMPERATURE值,进一步约束模型输出,同时优化提取字段的描述,明确输出要求
  3. PDF 文件提取内容不全:针对纯图片扫描件 PDF,需先通过 OCR 工具提取文本,再进行结构化提取,原生 PDF 可直接使用内置函数提取全量内容
  4. 批量处理时文件被跳过:检查文件后缀是否在支持的格式列表内,工具会自动跳过隐藏文件与不支持的格式,可通过控制台打印的日志查看处理详情

七、总结

本文从零到一开发了一款覆盖全场景的 AI 多模态结构化数据提取工具,解决了职场人日常工作中最头疼的非结构化内容处理痛点,所有代码均可直接复用,高度可定制,无论是个人办公自动化,还是企业级业务流程集成,都能快速适配。

整个开发过程中,我们可以清晰看到 4SAPI 给开发者带来的核心价值:开箱即用的全量模型能力,零成本的迁移适配成本。无需关注底层的多模态接口适配、跨境网络优化、多模型兼容等问题,只需专注于业务逻辑本身,就能快速开发出实用的 AI 工具。

对于个人开发者和中小企业而言,选用 4SAPI 作为大模型接入层,不仅能大幅降低开发与运维成本,还能一键解锁全球顶尖的多模态、长文本大模型能力,用 AI 真正提升办公与开发效率,告别重复机械的手动工作。