Python实现Excel转JSON 同维度聚合求和适配Telegram机器人
问题概述
- 现有
.xlsx格式业务数据样例如下:
- 需将Excel转换为结构化JSON,供Telegram机器人使用:机器人按顺序询问用户设备品牌、设备名称、查询月份三个条件,匹配后返回对应设备单价、总金额。
- 原有代码存在运行报错,且未实现核心聚合规则:相同设备名称、相同月份的重复记录,需要对device_price、device_summ字段求和合并。
原有代码问题排查
- 行遍历范围错误:
range(2, maxrows)会遗漏最后一行数据,openpyxl行号从1计数,正确遍历范围应为range(2, maxrows + 1) - 存在未定义变量:代码中引用了从未赋值的
device_price_uah、device_summ_uah,运行时直接触发NameError - 月份处理逻辑硬编码:仅判断了2020年10月、11月两个月份,无法适配其他月份数据
- 无聚合逻辑:以行号为存储key,相同设备、相同月份的重复记录不会合并
- 输出结构不利于查询:以行号为key的字典结构,机器人查询时需要遍历所有键做匹配,效率低
修正后完整代码
from openpyxl import load_workbook import json from datetime import datetime # 加载Excel文件,data_only=True读取单元格计算后的值,避免公式读取异常 wb = load_workbook('data.xlsx', data_only=True) ws = wb.active maxrows = ws.max_row print(f"Excel文件总行数(含表头):{maxrows}") # 聚合存储字典,使用(设备品牌, 设备名称, 月份标识)作为唯一键做聚合 aggregated_data = {} # 遍历所有数据行(表头为第1行,从第2行开始遍历到最后一行) for row_idx in range(2, maxrows + 1): # 读取单元格值,数值字段空值兜底为0 device_name = ws[f'A{row_idx}'].value device_brand = ws[f'B{row_idx}'].value device_price_usd = ws[f'C{row_idx}'].value or 0 device_summ_usd = ws[f'D{row_idx}'].value or 0 month_cell_val = ws[f'E{row_idx}'].value # 跳过缺核心字段的空行/无效行 if not all([device_name, device_brand, month_cell_val]): continue # 自动转换月份格式,生成类似oct_2020、nov_2020的标识,无需硬编码判断 if isinstance(month_cell_val, datetime): date_obj = month_cell_val else: # 兼容字符串格式的日期值 date_obj = datetime.strptime(str(month_cell_val).split()[0], "%Y-%m-%d") month_key = f"{date_obj.strftime('%b').lower()}_{date_obj.year}" # 生成聚合唯一键 agg_key = (device_brand, device_name, month_key) if agg_key not in aggregated_data: # 键不存在则初始化记录 aggregated_data[agg_key] = { "device_name": device_name, "device_brand": device_brand, "device_price_usd": float(device_price_usd), "device_summ_usd": float(device_summ_usd), "month": month_key } else: # 键已存在则累加金额字段,实现同设备同月份记录合并 aggregated_data[agg_key]["device_price_usd"] += float(device_price_usd) aggregated_data[agg_key]["device_summ_usd"] += float(device_summ_usd) # 转换为列表结构,方便Telegram机器人遍历查询 final_data = list(aggregated_data.values()) # 写入JSON文件,指定utf-8编码避免中文乱码 with open("data.json", "w", encoding="utf-8") as file: json.dump(final_data, file, indent=4, ensure_ascii=False) print(f"数据处理完成,共生成{len(final_data)}条聚合后有效记录,已写入data.json")
使用说明
- 代码默认读取同目录下的
data.xlsx文件,运行后在同目录生成data.json结果文件 - 月份格式自动识别转换,支持所有公历月份,无需手动添加判断分支
- 自动对同品牌、同设备名、同月份的记录做金额累加,满足聚合要求
- 最终输出的JSON为列表结构,机器人查询时可直接遍历匹配三个条件返回结果,参考查询逻辑:
# Telegram机器人查询逻辑示例 def get_matched_record(target_brand, target_name, target_month): for item in final_data: if item["device_brand"] == target_brand and item["device_name"] == target_name and item["month"] == target_month: return f"匹配结果:\n设备单价(USD):{item['device_price_usd']}\n总金额(USD):{item['device_summ_usd']}" return "未查询到符合条件的设备记录"
内容的提问来源于stack exchange,提问作者Nik
相关产品推荐
相关产品推荐

