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)
相关推荐
一晌小贪欢3 小时前
Python爬虫第7课:多线程与异步爬虫技术
开发语言·爬虫·python·网络爬虫·python爬虫·python3
RECRUITGUY4 小时前
Excel中将毫秒时间戳转换为标准时间格式
excel
yanxing.D6 小时前
OpenCV轻松入门_面向python(第六章 阈值处理)
人工智能·python·opencv·计算机视觉
SunkingYang6 小时前
详细介绍C++中捕获异常类型的方式有哪些,分别用于哪些情形,哪些异常捕获可用于通过OLE操作excel异常
c++·excel·mfc·异常捕获·comerror
JJJJ_iii7 小时前
【机器学习01】监督学习、无监督学习、线性回归、代价函数
人工智能·笔记·python·学习·机器学习·jupyter·线性回归
Python图像识别10 小时前
71_基于深度学习的布料瑕疵检测识别系统(yolo11、yolov8、yolov5+UI界面+Python项目源码+模型+标注好的数据集)
python·深度学习·yolo
千码君201611 小时前
React Native:从react的解构看编程众多语言中的解构
java·javascript·python·react native·react.js·解包·解构
淮北49411 小时前
windows安装minicoda
windows·python·conda
lied166363480612 小时前
List导出到Excel文件
servlet·list·excel