json转excel python pd
pip install pandas openpyxl
简单实现
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")
实现
# 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)breakelse:# 如果没有列表,将整个字典转换为单行DataFramedf = pd.DataFrame([json_data])elif isinstance(json_data, list):# 直接用列表创建DataFramedf = 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_pathexcept 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_datain: bodyrequired: truedescription: JSON格式的数据- name: filenamein: querytype: stringrequired: falsedefault: output.xlsxdescription: 输出的Excel文件名responses:200:description: 成功生成Excel文件content:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:schema:type: stringformat: binary400: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: datain: bodyrequired: truedescription: LLM返回的结构化数据- name: filenamein: querytype: stringrequired: falsedefault: structured_data.xlsxdescription: 输出的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: filepathin: querytype: stringrequired: truedescription: 本地JSON文件的路径- name: filenamein: querytype: stringrequired: falsedefault: output.xlsxdescription: 输出的Excel文件名responses:200:description: 成功生成Excel文件content:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:schema:type: stringformat: binary400: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)}"}), 400except 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_dataexcept Exception as e:logger.error(f"计算钢材重量和长度时出错: {str(e)}")raise edef _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.00000785total_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: datain: bodyrequired: truedescription: 包含钢材信息的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: datain: bodyrequired: truedescription: 包含钢材信息的JSON数据- name: filenamein: querytype: stringrequired: falsedefault: steel_data.xlsxdescription: 输出的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)