#!/usr/bin/env python3 # 一次性:从 运营/Voypace/Voypace投放计划.xlsx 的 Sheet4 生成初始 mtg_data.json # 之后的每日增量由 adscenter_daily_sync.py 负责。 import openpyxl, json, os, datetime XLSX = "/Users/wangyuan/Documents/SHAREit/运营/Voypace/Voypace投放计划.xlsx" HERE = os.path.dirname(os.path.abspath(__file__)) camps = json.load(open(os.path.join(HERE, "campaigns.json"))) CAMPS = {r["campid"]: r for r in camps} # 渠道名归一:Sheet4 用 Mediago,campaigns 用 MediaGo CH_NORM = {"mediago": "MediaGo", "mintegral": "Mintegral", "bigo": "Bigo"} # 无 campid 行的兜底:按 (包名, 渠道) 反查 campid BY_PKG_CH = {(r["pkg"], r["channel"]): r["campid"] for r in camps} base = datetime.date(1899, 12, 30) def to_date(v): if isinstance(v, (int, float)): return (base + datetime.timedelta(days=int(v))).isoformat() if isinstance(v, (datetime.datetime, datetime.date)): return v.strftime("%Y-%m-%d") return str(v)[:10] def num(v): try: return float(str(v).replace(",", "").strip() or 0) except: return 0.0 wb = openpyxl.load_workbook(XLSX, data_only=True) ws = wb["Sheet4"] rows = list(ws.iter_rows(values_only=True)) cur_date = None out = {} for r in rows[1:]: # 列: 0时间 1单价 2地区 3包名 4OS 5AdpingID 6投放平台 7Imp 8Clk 9CTR 10Install 11CVR 12Spend 13oCPI if r[0] not in (None, ""): cur_date = to_date(r[0]) pkg = (str(r[3]).strip() if r[3] else "") loc = (str(r[2]).strip().upper() if r[2] else "") adping = (str(r[5]).strip() if r[5] else "") ch_raw = (str(r[6]).strip() if r[6] else "") ch = CH_NORM.get(ch_raw.lower(), ch_raw) if not ch or not cur_date: continue # 定位 campid cid = adping.split(".")[0] if adping else "" if cid not in CAMPS: # 兜底:靠 包名+渠道(处理 Avito 那种 campid 为 campaign_name 的行) # 包名可能带 (APK)等后缀,取主体 pkg_main = pkg.split("(")[0].split("(")[0].strip() cid = BY_PKG_CH.get((pkg_main, ch), "") if cid not in CAMPS: continue info = CAMPS[cid] imp = int(num(r[7])); clk = int(num(r[8])); cv = int(num(r[10])); sp = round(num(r[12]), 2) if not loc: loc = str(info.get("geo", "")).upper() key = (cur_date, info["channel"], cid, loc) a = out.get(key) if a: a["impression"] += imp; a["clicks"] += clk; a["conversions"] += cv; a["spend"] = round(a["spend"] + sp, 2) else: out[key] = { "date": cur_date, "channel": info["channel"], "campid": cid, "offer_name": f'{cid}_{info["product"]}', "product": info["product"], "pkg": info["pkg"], "location": loc, "bid_type": "", "impression": imp, "clicks": clk, "conversions": cv, "spend": sp, } data = [] for a in out.values(): imp, clk, cv = a["impression"], a["clicks"], a["conversions"] a["ctr"] = round(clk/imp, 5) if imp else 0.0 a["cvr"] = round(cv/clk, 5) if clk else 0.0 data.append(a) data.sort(key=lambda x: (x["date"], x["channel"], -x["impression"])) json.dump(data, open(os.path.join(HERE, "mtg_data.json"), "w"), ensure_ascii=False, indent=2) print(f"生成 {len(data)} 条 -> mtg_data.json")