#!/bin/sh set -eu SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) TMP_FILE="$SCRIPT_DIR/data.json.tmp" OUTPUT_FILE="$SCRIPT_DIR/data.json" python3 - "$TMP_FILE" <<'PY' import csv import json import re import sys import urllib.request from collections import defaultdict from datetime import datetime, timedelta from zoneinfo import ZoneInfo CSV_URL = ( "https://docs.google.com/spreadsheets/d/" "1KaNOwaZ3DqjTXRK8XhF1OGF9qUmOh0NLXOgxVrh14h0/" "export?format=csv&gid=1445753035" ) TIMEZONE = ZoneInfo("Asia/Shanghai") DAYS = 14 BLOCKS = [ {"country": "KZ", "date": 2, "geo": 3, "installs": 5, "spend": 8, "cac": 10}, {"country": "UZ", "date": 14, "geo": 15, "installs": 17, "spend": 18, "cac": 20}, {"country": "KG", "date": 25, "geo": 26, "installs": 28, "spend": 29, "cac": 31}, {"country": "AM", "date": 35, "geo": 36, "installs": 38, "spend": 39, "cac": 41}, ] def parse_date(value): text = str(value or "").strip() for fmt in ("%Y/%m/%d", "%Y-%m-%d", "%Y%m%d", "%m/%d/%Y"): try: return datetime.strptime(text, fmt).date() except ValueError: pass match = re.fullmatch(r"(\d{4})[/.-](\d{1,2})[/.-](\d{1,2})", text) if not match: return None try: return datetime(*map(int, match.groups())).date() except ValueError: return None def parse_number(value): text = str(value or "").strip().replace("\xa0", "").replace(",", "") if not text or text in {"-", "—"}: return None negative = text.startswith("(") and text.endswith(")") cleaned = re.sub(r"[^0-9.\-]", "", text) try: number = float(cleaned) return -number if negative else number except ValueError: return None def cell(row, index): return row[index] if index < len(row) else "" request = urllib.request.Request(CSV_URL, headers={"User-Agent": "AgentStage-Ozon-Report/1.0"}) with urllib.request.urlopen(request, timeout=90) as response: text = response.read().decode("utf-8-sig") rows = list(csv.reader(text.splitlines())) now = datetime.now(TIMEZONE) end_date = now.date() - timedelta(days=1) start_date = end_date - timedelta(days=DAYS - 1) aggregated = defaultdict(lambda: {"installs": 0.0, "spend": 0.0, "cac_values": []}) for row in rows: for block in BLOCKS: day = parse_date(cell(row, block["date"])) if day is None or not (start_date <= day <= end_date): continue country = str(cell(row, block["geo"])).strip().upper() or block["country"] if country != block["country"]: continue key = (country, day.isoformat()) installs = parse_number(cell(row, block["installs"])) spend = parse_number(cell(row, block["spend"])) cac = parse_number(cell(row, block["cac"])) aggregated[key]["installs"] += installs or 0 aggregated[key]["spend"] += spend or 0 if cac is not None: aggregated[key]["cac_values"].append(cac) records = [] for country in [item["country"] for item in BLOCKS]: for offset in range(DAYS): day = (start_date + timedelta(days=offset)).isoformat() values = aggregated.get((country, day), {"installs": 0, "spend": 0, "cac_values": []}) cac_values = values["cac_values"] records.append({ "date": day, "country": country, "installs": round(values["installs"], 2), "spend": round(values["spend"], 4), "cac": round(sum(cac_values) / len(cac_values), 4) if cac_values else None, }) summary = [] for country in [item["country"] for item in BLOCKS]: country_rows = [row for row in records if row["country"] == country] cac_values = [row["cac"] for row in country_rows if row["cac"] is not None] summary.append({ "country": country, "installs": round(sum(row["installs"] for row in country_rows), 2), "spend": round(sum(row["spend"] for row in country_rows), 4), "avg_cac": round(sum(cac_values) / len(cac_values), 4) if cac_values else None, "cac_days": len(cac_values), }) payload = { "title": "Ozon · 过去14天国家投放表现", "generated_at": now.isoformat(timespec="seconds"), "timezone": "Asia/Shanghai", "period": {"start": start_date.isoformat(), "end": end_date.isoformat(), "days": DAYS}, "countries": [item["country"] for item in BLOCKS], "summary": summary, "records": records, "definitions": { "installs": "Google Sheet 各国家区块的 Install", "spend": "Google Sheet 各国家区块的 Daily Spend(USD)", "cac": "Google Sheet 各国家区块的 CAC from client report;汇总值为有数据日期的日均 CAC", }, } with open(sys.argv[1], "w", encoding="utf-8") as handle: json.dump(payload, handle, ensure_ascii=False, indent=2) PY mv "$TMP_FILE" "$OUTPUT_FILE" echo "Updated $OUTPUT_FILE"