Files
2026-09-10 15:26:54 +08:00

78 lines
3.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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")