json转excel python pd

python 复制代码
pip install pandas openpyxl

简单实现

python 复制代码
import pandas as pd

# JSON 数据
data = [
    {
        "id": 1,
        "age": 3,
        "male": True,
        "address": "shanghai"
    },
    {
        "id": 2,
        "age": 50,
        "male": True,
        "address": "Washington D.C."
    },
    {
        "id": 3,
        "age": 15,
        "male": False,
        "address": "hongkong"
    },
    {
        "id": 4,
        "age": 19,
        "male": False,
        "address": "newyork"
    },
    {
        "id": 5,
        "age": 38,
        "male": True,
        "address": "beijing"
    }
]

# 转换为 DataFrame
df = pd.DataFrame(data)

# 保存为 Excel 文件
df.to_excel("output.xlsx", index=False)

print("✅ JSON 数据已成功保存为 output.xlsx")

实现

python 复制代码
# file: json_to_excel_service.py
import pandas as pd
import json
from flask import Flask, request, jsonify, send_file
import os
import logging

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = Flask(__name__)

def save_json_to_excel(json_data, filename="output.xlsx"):
    """
    将JSON数据保存为Excel文件
    
    Args:
        json_data (list/dict): JSON格式的数据
        filename (str): 输出的Excel文件名
    
    Returns:
        str: 生成的Excel文件路径
    """
    try:
        # 如果输入是JSON字符串,则解析为Python对象
        if isinstance(json_data, str):
            json_data = json.loads(json_data)
        
        # 如果是字典且包含列表数据,需要特殊处理
        if isinstance(json_data, dict):
            # 如果字典中的值是列表,使用第一个列表
            if any(isinstance(v, list) for v in json_data.values()):
                # 找到第一个列表值作为数据源
                for value in json_data.values():
                    if isinstance(value, list):
                        df = pd.DataFrame(value)
                        break
            else:
                # 如果没有列表,将整个字典转换为单行DataFrame
                df = pd.DataFrame([json_data])
        elif isinstance(json_data, list):
            # 直接用列表创建DataFrame
            df = pd.DataFrame(json_data)
        else:
            raise ValueError("不支持的数据格式")
            
        # 保存为Excel文件
        output_path = os.path.abspath(filename)
        df.to_excel(output_path, index=False)
        logger.info(f"Excel文件已保存至: {output_path}")
        return output_path
        
    except Exception as e:
        logger.error(f"保存Excel文件时出错: {str(e)}")
        raise e

@app.route('/json_to_excel', methods=['POST'])
def convert_json_to_excel():
    """
    接收JSON数据并转换为Excel文件的API接口
    
    ---
    parameters:
      - name: json_data
        in: body
        required: true
        description: JSON格式的数据
      - name: filename
        in: query
        type: string
        required: false
        default: output.xlsx
        description: 输出的Excel文件名
    responses:
      200:
        description: 成功生成Excel文件
        content:
          application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:
            schema:
              type: string
              format: binary
      400:
        description: 请求参数错误
      500:
        description: 服务器内部错误
    """
    try:
        # 获取请求体中的JSON数据
        if request.is_json:
            json_data = request.get_json()
        else:
            return jsonify({"error": "请求必须包含JSON数据"}), 400
            
        # 获取查询参数中的文件名
        filename = request.args.get('filename', 'output.xlsx')
        
        # 确保文件名以.xlsx结尾
        if not filename.endswith('.xlsx'):
            filename += '.xlsx'
            
        # 调用转换函数
        file_path = save_json_to_excel(json_data, filename)
        
        # 返回文件下载
        return send_file(file_path, as_attachment=True, download_name=filename)
        
    except Exception as e:
        logger.error(f"处理请求时出错: {str(e)}")
        return jsonify({"error": f"处理过程中出错: {str(e)}"}), 500

@app.route('/save_structured_data', methods=['POST'])
def save_structured_data():
    """
    专门用于保存getthickpart服务中LLM返回的结构化数据为Excel文件
    
    ---
    parameters:
      - name: data
        in: body
        required: true
        description: LLM返回的结构化数据
      - name: filename
        in: query
        type: string
        required: false
        default: structured_data.xlsx
        description: 输出的Excel文件名
    responses:
      200:
        description: 成功保存Excel文件
      400:
        description: 请求参数错误
      500:
        description: 服务器内部错误
    """
    try:
        # 获取请求体中的JSON数据
        if request.is_json:
            request_data = request.get_json()
        else:
            return jsonify({"error": "请求必须包含JSON数据"}), 400
            
        # 提取结构化数据
        if 'structured_data' in request_data:
            structured_data = request_data['structured_data']
        else:
            structured_data = request_data
            
        # 获取查询参数中的文件名
        filename = request.args.get('filename')
        if not filename:
            # 如果没有指定文件名,使用默认命名规则
            filename = 'structured_data.xlsx'
        
        # 确保文件名以.xlsx结尾
        if not filename.endswith('.xlsx'):
            filename += '.xlsx'
            
        # 调用转换函数
        file_path = save_json_to_excel(structured_data, filename)
        
        # 返回成功信息
        return jsonify({
            "status": "success",
            "message": f"数据已成功保存为Excel文件: {filename}",
            "file_path": file_path
        })
        
    except Exception as e:
        logger.error(f"处理请求时出错: {str(e)}")
        return jsonify({"error": f"处理过程中出错: {str(e)}"}), 500
@app.route('/json_file_to_excel', methods=['GET'])
def convert_json_file_to_excel():
    """
    读取本地JSON文件并转换为Excel文件的API接口
    
    ---
    parameters:
      - name: filepath
        in: query
        type: string
        required: true
        description: 本地JSON文件的路径
      - name: filename
        in: query
        type: string
        required: false
        default: output.xlsx
        description: 输出的Excel文件名
    responses:
      200:
        description: 成功生成Excel文件
        content:
          application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:
            schema:
              type: string
              format: binary
      400:
        description: 请求参数错误
      404:
        description: 文件未找到
      500:
        description: 服务器内部错误
    """
    try:
        # 获取查询参数
        filepath = request.args.get('filepath')
        filename = request.args.get('filename', 'output.xlsx')
        
        # 检查必要参数
        if not filepath:
            return jsonify({"error": "必须提供filepath参数"}), 400
            
        # 检查文件是否存在
        if not os.path.exists(filepath):
            return jsonify({"error": f"文件未找到: {filepath}"}), 404
            
        # 确保文件名以.xlsx结尾
        if not filename.endswith('.xlsx'):
            filename += '.xlsx'
            
        # 读取JSON文件
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                json_data = json.load(f)
        except json.JSONDecodeError as e:
            return jsonify({"error": f"JSON文件格式错误: {str(e)}"}), 400
        except Exception as e:
            return jsonify({"error": f"读取文件时出错: {str(e)}"}), 500
            
        # 调用转换函数
        file_path = save_json_to_excel(json_data, filename)
        
        # 返回文件下载
        return send_file(file_path, as_attachment=True, download_name=filename)
        
    except Exception as e:
        logger.error(f"处理请求时出错: {str(e)}")
        return jsonify({"error": f"处理过程中出错: {str(e)}"}), 500
@app.route('/health', methods=['GET'])
def health_check():
    """
    健康检查接口
    """
    return jsonify({"status": "healthy", "service": "json_to_excel_service"})

def calculate_steel_weights_and_lengths(json_data):
    """
    计算钢材的单重、总重或总长度
    
    对于钢板类型:
    - 单重 = 长度 * 宽度 * 厚度 * 0.00000785
    - 总重 = 单重 * 数量
    
    对于角钢类型:
    - 总长 = 长度 * 数量
    
    Args:
        json_data (list/dict): 包含钢材信息的JSON数据
        
    Returns:
        list/dict: 添加计算结果后的数据
    """
    try:
        # 处理输入数据
        if isinstance(json_data, str):
            json_data = json.loads(json_data)
            
        # 创建数据副本以避免修改原始数据
        processed_data = json_data
        
        # 如果是字典格式,检查是否包含列表数据
        if isinstance(processed_data, dict):
            # 遍历字典中的每个键值对
            for key, value in processed_data.items():
                if isinstance(value, list):
                    # 处理列表中的每个项目
                    for item in value:
                        if isinstance(item, dict):
                            _calculate_item_weight_or_length(item)
                elif isinstance(value, dict):
                    _calculate_item_weight_or_length(value)
                    
        elif isinstance(processed_data, list):
            # 处理列表中的每个项目
            for item in processed_data:
                if isinstance(item, dict):
                    _calculate_item_weight_or_length(item)
                    
        return processed_data
        
    except Exception as e:
        logger.error(f"计算钢材重量和长度时出错: {str(e)}")
        raise e

def _calculate_item_weight_or_length(item):
    """
    计算单个钢材项目的重量或长度
    
    Args:
        item (dict): 单个钢材项目的数据
    """
    try:
        steel_type = item.get('类型') or item.get('type') or item.get('steel_type')
        
        if steel_type == '钢板':
            # 获取必要参数
            length = float(item.get('长度') or item.get('length') or 0)
            width = float(item.get('宽度') or item.get('width') or 0)
            thickness = float(item.get('厚度') or item.get('thickness') or 0)
            quantity = float(item.get('数量') or item.get('quantity') or 0)
            
            # 计算单重和总重
            unit_weight = length * width * thickness * 0.00000785
            total_weight = unit_weight * quantity
            
            # 添加计算结果到项目中
            item['单重'] = round(unit_weight, 1)
            item['总重'] = round(total_weight, 1)
            
        elif steel_type == '角钢':
            # 获取必要参数
            length = float(item.get('长度') or item.get('length') or 0)
            quantity = float(item.get('数量') or item.get('quantity') or 0)
            
            # 计算总长
            total_length = length * quantity
            
            # 添加计算结果到项目中
            item['总长'] = round(total_length, 1)
            
    except Exception as e:
        logger.warning(f"计算单项钢材数据时出错: {str(e)}, 项目数据: {item}")
        # 不中断整个处理过程,继续处理其他项目
@app.route('/calculate_steel_data', methods=['POST'])
def calculate_steel_data_endpoint():
    """
    计算钢材数据(单重、总重、总长)并返回结果
    
    ---
    parameters:
      - name: data
        in: body
        required: true
        description: 包含钢材信息的JSON数据
    responses:
      200:
        description: 成功计算并返回结果
      400:
        description: 请求参数错误
      500:
        description: 服务器内部错误
    """
    try:
        # 获取请求体中的JSON数据
        if request.is_json:
            json_data = request.get_json()
        else:
            return jsonify({"error": "请求必须包含JSON数据"}), 400
            
        # 计算钢材重量和长度
        calculated_data = calculate_steel_weights_and_lengths(json_data)
        
        # 返回计算结果
        return jsonify({
            "status": "success",
            "data": calculated_data
        })
        
    except Exception as e:
        logger.error(f"处理钢材计算请求时出错: {str(e)}")
        return jsonify({"error": f"处理过程中出错: {str(e)}"}), 500

@app.route('/calculate_and_save_steel_data', methods=['POST'])
def calculate_and_save_steel_data():
    """
    计算钢材数据并保存为Excel文件
    
    ---
    parameters:
      - name: data
        in: body
        required: true
        description: 包含钢材信息的JSON数据
      - name: filename
        in: query
        type: string
        required: false
        default: steel_data.xlsx
        description: 输出的Excel文件名
    responses:
      200:
        description: 成功保存Excel文件
      400:
        description: 请求参数错误
      500:
        description: 服务器内部错误
    """
    try:
        # 获取请求体中的JSON数据
        if request.is_json:
            request_data = request.get_json()
        else:
            return jsonify({"error": "请求必须包含JSON数据"}), 400
            
        # 获取查询参数中的文件名
        filename = request.args.get('filename')
        if not filename:
            filename = 'steel_data.xlsx'
        
        # 确保文件名以.xlsx结尾
        if not filename.endswith('.xlsx'):
            filename += '.xlsx'
            
        # 计算钢材重量和长度
        calculated_data = calculate_steel_weights_and_lengths(request_data)
        
        # 保存为Excel文件
        file_path = save_json_to_excel(calculated_data, filename)
        
        # 返回文件下载
        return send_file(file_path, as_attachment=True, download_name=filename)
        
    except Exception as e:
        logger.error(f"处理钢材计算和保存请求时出错: {str(e)}")
        return jsonify({"error": f"处理过程中出错: {str(e)}"}), 500
if __name__ == "__main__":
    # 在5005端口运行服务
    app.run(host='0.0.0.0', port=5005, debug=True)
相关推荐
明月_清风28 分钟前
FastAPI 从入门到实战:3 分钟构建高性能异步 API
后端·python·fastapi
bellus-35 分钟前
ubuntu26测试win10的ollama大模型性能
python
水木流年追梦36 分钟前
大模型入门-Reward 奖励模型训练
开发语言·python·算法·leetcode·正则表达式
JavaWeb学起来36 分钟前
Python学习教程(六)数据结构List(列表)
数据结构·python·python基础·python教程
liuyunshengsir1 小时前
PyTorch 动态量化(Dynamic Quantization)
人工智能·pytorch·python
电子云与长程纠缠1 小时前
UE5制作六边形包裹球体效果
开发语言·python·ue5
DFT计算杂谈1 小时前
KPROJ编译教程
java·前端·python·算法·conda
念恒123062 小时前
Python(循环中断)
开发语言·python
tsfy20032 小时前
Python 处理中文文件名的3个坑(附 Flask 上传解决函数)
开发语言·python·flask·文件上传·中文编码
AI技术控2 小时前
KV Cache 缓存机制的原理和应用:从 Transformer 推理到大模型服务优化
人工智能·python·深度学习·缓存·自然语言处理·transformer