# -*- coding: utf-8 -*- """从美团「城市字典」Excel 生成随仓库的 JSON(app/integrations/data/meituan_cities.json)。 本地一次性工具:美团每年更新城市字典时,把新 Excel 放进来重跑即可。 Excel 不入库、不进仓库(二进制、需 openpyxl);生成的 JSON 随仓库提交,部署到服务器后 ETL(scripts/pull_meituan_coupons.py)直接读它遍历全部城市。 字典口径:359 个地级市,经实测一个地级市 cityId 已覆盖其下辖县级市(如徐州→邳州/新沂), 故无需区县层级。 用法: python tools/gen_meituan_cities.py ["城市字典xxx.xlsx" 路径] (不传则用默认 e:\\codes\\城市字典2025 (1).xlsx) """ from __future__ import annotations import json import os import sys import openpyxl HERE = os.path.dirname(os.path.abspath(__file__)) ROOT = os.path.dirname(HERE) DEFAULT_EXCEL = r"e:\codes\城市字典2025 (1).xlsx" OUT = os.path.join(ROOT, "app", "integrations", "data", "meituan_cities.json") def main() -> None: excel = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_EXCEL wb = openpyxl.load_workbook(excel, data_only=True) ws = wb.worksheets[0] rows = list(ws.iter_rows(values_only=True)) header = rows[0] cities = [] seen = set() for r in rows[1:]: cid = str(r[0]).strip() if r[0] else "" name = str(r[1]).strip() if len(r) > 1 and r[1] else "" prov = str(r[2]).strip() if len(r) > 2 and r[2] else "" if not cid or cid in seen: continue seen.add(cid) cities.append({"city_id": cid, "name": name, "province": prov}) os.makedirs(os.path.dirname(OUT), exist_ok=True) with open(OUT, "w", encoding="utf-8") as f: json.dump(cities, f, ensure_ascii=False, indent=1) print(f"表头: {header}") print(f"写出 {len(cities)} 城 → {OUT}") print("样例:", cities[:3]) if __name__ == "__main__": main()