Update Sep 2026 data; auto-fetch from Google Sheet; daily refresh
This commit is contained in:
@@ -2,16 +2,223 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"geo": "EG",
|
"geo": "EG",
|
||||||
"product": "Nagwa",
|
"product": "Nagwa",
|
||||||
"price": 0.30,
|
"sep_budget": 7500,
|
||||||
"sep_budget": 7500.00,
|
"spend": 2279.6,
|
||||||
"spend": 814.80,
|
"left": 5220.4,
|
||||||
"left": 6685.20,
|
"spend_pct": "30.39%",
|
||||||
"spend_pct": "10.86%",
|
"rec_daily_install": 593.23,
|
||||||
"rec_daily_install": 825.33
|
"price": 0.4
|
||||||
},
|
},
|
||||||
"daily": [
|
"daily": [
|
||||||
{"date": "2026-09-01", "install": 932, "payable_spend": 279.60, "enroll_session": 698, "enroll_session_pct": 74.89},
|
{
|
||||||
{"date": "2026-09-02", "install": 917, "payable_spend": 275.10, "enroll_session": 0, "enroll_session_pct": 0.00},
|
"date": "2026-09-01",
|
||||||
{"date": "2026-09-03", "install": 867, "payable_spend": 260.10, "enroll_session": 0, "enroll_session_pct": 0.00}
|
"install": 932,
|
||||||
|
"payable_spend": 279.6,
|
||||||
|
"enroll_session": 698,
|
||||||
|
"enroll_session_pct": 74.89
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-02",
|
||||||
|
"install": 917,
|
||||||
|
"payable_spend": 275.1,
|
||||||
|
"enroll_session": 586,
|
||||||
|
"enroll_session_pct": 63.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-03",
|
||||||
|
"install": 867,
|
||||||
|
"payable_spend": 260.1,
|
||||||
|
"enroll_session": 502,
|
||||||
|
"enroll_session_pct": 57.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-04",
|
||||||
|
"install": 822,
|
||||||
|
"payable_spend": 246.6,
|
||||||
|
"enroll_session": 676,
|
||||||
|
"enroll_session_pct": 82.24
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-05",
|
||||||
|
"install": 894,
|
||||||
|
"payable_spend": 268.2,
|
||||||
|
"enroll_session": 760,
|
||||||
|
"enroll_session_pct": 85.01
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-06",
|
||||||
|
"install": 1048,
|
||||||
|
"payable_spend": 314.4,
|
||||||
|
"enroll_session": 782,
|
||||||
|
"enroll_session_pct": 74.62
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-07",
|
||||||
|
"install": 858,
|
||||||
|
"payable_spend": 343.2,
|
||||||
|
"enroll_session": 866,
|
||||||
|
"enroll_session_pct": 100.93
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-08",
|
||||||
|
"install": 731,
|
||||||
|
"payable_spend": 292.4,
|
||||||
|
"enroll_session": 651,
|
||||||
|
"enroll_session_pct": 89.06
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-09",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-10",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-11",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-12",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-13",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-14",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-15",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-16",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-17",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-18",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-19",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-20",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-21",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-22",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-23",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-24",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-25",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-26",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-27",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-28",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-29",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-30",
|
||||||
|
"install": 0,
|
||||||
|
"payable_spend": 0.0,
|
||||||
|
"enroll_session": 0,
|
||||||
|
"enroll_session_pct": 0.0
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
03
|
24
|
||||||
|
|||||||
@@ -1,6 +1,120 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# update.sh - 数据来自手动更新的 data.json
|
# update.sh - 自动从 Google Sheet 拉取 EG Nagwa 当月数据并生成 data.json
|
||||||
# 由于数据源是 Excel 表格(无公开 API),此脚本仅做占位
|
# 数据源:公开导出的 Google Sheet CSV
|
||||||
# 每次有新数据时,直接更新 data.json 并 push 即可
|
# 每天由服务器自动执行一次(见 schedule.conf)
|
||||||
echo "data.json is manually maintained from Excel export."
|
set -euo pipefail
|
||||||
echo "Last check: $(date)"
|
|
||||||
|
SHEET_ID="11Npr4IpXT8jtgUnrkrjITJ8s1fHNYTwRRwSGIvcfeIs"
|
||||||
|
GID="699511110"
|
||||||
|
CSV_URL="https://docs.google.com/spreadsheets/d/${SHEET_ID}/export?format=csv&gid=${GID}"
|
||||||
|
|
||||||
|
OUT="data.json"
|
||||||
|
TMP_CSV="$(mktemp)"
|
||||||
|
trap 'rm -f "$TMP_CSV"' EXIT
|
||||||
|
|
||||||
|
# 当月,格式如 September-2026
|
||||||
|
MONTH_TAG="$(date +%B-%Y)"
|
||||||
|
|
||||||
|
echo "Fetching CSV for month: $MONTH_TAG"
|
||||||
|
curl -fsSL "$CSV_URL" -o "$TMP_CSV"
|
||||||
|
|
||||||
|
# 用 python 解析 CSV 生成 data.json(python3 处理带引号/逗号的字段更稳妥)
|
||||||
|
python3 - "$TMP_CSV" "$OUT" "$MONTH_TAG" <<'PY'
|
||||||
|
import csv, json, sys, re
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
csv_path, out_path, month_tag = sys.argv[1], sys.argv[2], sys.argv[3]
|
||||||
|
|
||||||
|
def num(s):
|
||||||
|
if s is None: return None
|
||||||
|
s = s.strip().replace(',', '').replace('$', '').replace('%', '')
|
||||||
|
if s == '': return None
|
||||||
|
try:
|
||||||
|
f = float(s)
|
||||||
|
return int(f) if f.is_integer() else f
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
rows = list(csv.reader(open(csv_path, newline='', encoding='utf-8')))
|
||||||
|
|
||||||
|
# 列索引(0-based),依据表头布局:
|
||||||
|
# Month=7, DT=8, Geo=9, Install=10, Price=11, MidasSpend=12,
|
||||||
|
# PayableSpend=13, Enroll_Session=14, Enroll_Session%=15, Remark=16,
|
||||||
|
# meta-key=17, meta-value=18
|
||||||
|
COL_MONTH, COL_DT, COL_INSTALL = 7, 8, 10
|
||||||
|
COL_PAYABLE, COL_ENROLL, COL_ENROLLPCT = 13, 14, 15
|
||||||
|
COL_METAK, COL_METAV = 16, 17
|
||||||
|
|
||||||
|
daily = []
|
||||||
|
meta = {"geo": "EG", "product": "Nagwa"}
|
||||||
|
|
||||||
|
# 从 month_tag 解析目标年月,用于把 DT(如 2026/9/1 或 20260901)标准化成 YYYY-MM-DD
|
||||||
|
target_month = datetime.strptime(month_tag, "%B-%Y")
|
||||||
|
ty, tm = target_month.year, target_month.month
|
||||||
|
|
||||||
|
def parse_dt(dt):
|
||||||
|
dt = dt.strip()
|
||||||
|
if not dt: return None
|
||||||
|
# 形如 2026/9/1
|
||||||
|
m = re.match(r'^(\d{4})/(\d{1,2})/(\d{1,2})$', dt)
|
||||||
|
if m:
|
||||||
|
y, mo, d = map(int, m.groups())
|
||||||
|
return f"{y:04d}-{mo:02d}-{d:02d}"
|
||||||
|
# 形如 20260901
|
||||||
|
m = re.match(r'^(\d{4})(\d{2})(\d{2})$', dt)
|
||||||
|
if m:
|
||||||
|
y, mo, d = map(int, m.groups())
|
||||||
|
return f"{y:04d}-{mo:02d}-{d:02d}"
|
||||||
|
return None
|
||||||
|
|
||||||
|
price_seen = None
|
||||||
|
for r in rows:
|
||||||
|
if len(r) <= COL_ENROLLPCT:
|
||||||
|
continue
|
||||||
|
if r[COL_MONTH].strip() != month_tag:
|
||||||
|
continue
|
||||||
|
date = parse_dt(r[COL_DT])
|
||||||
|
if not date:
|
||||||
|
continue
|
||||||
|
install = num(r[COL_INSTALL]) or 0
|
||||||
|
spend = num(r[COL_PAYABLE]) or 0.0
|
||||||
|
enroll = num(r[COL_ENROLL]) or 0
|
||||||
|
pct = num(r[COL_ENROLLPCT]) or 0.0
|
||||||
|
daily.append({
|
||||||
|
"date": date,
|
||||||
|
"install": int(install),
|
||||||
|
"payable_spend": round(float(spend), 2),
|
||||||
|
"enroll_session": int(enroll),
|
||||||
|
"enroll_session_pct": round(float(pct), 2),
|
||||||
|
})
|
||||||
|
# 记录价格(取当月出现的最新价)
|
||||||
|
p = num(r[11])
|
||||||
|
if p is not None:
|
||||||
|
price_seen = p
|
||||||
|
# 抓取 meta(Remark 区块的 key/value)
|
||||||
|
k = r[COL_METAK].strip() if len(r) > COL_METAK else ""
|
||||||
|
v = r[COL_METAV].strip() if len(r) > COL_METAV else ""
|
||||||
|
if k and v:
|
||||||
|
kl = k.lower()
|
||||||
|
if "budget" in kl:
|
||||||
|
meta["sep_budget"] = num(v)
|
||||||
|
elif kl == "spend":
|
||||||
|
meta["spend"] = num(v)
|
||||||
|
elif kl == "left":
|
||||||
|
meta["left"] = num(v)
|
||||||
|
elif kl == "%":
|
||||||
|
meta["spend_pct"] = v if v.endswith('%') else (v + '%')
|
||||||
|
elif "daily install" in kl:
|
||||||
|
meta["rec_daily_install"] = num(v)
|
||||||
|
|
||||||
|
if price_seen is not None:
|
||||||
|
meta["price"] = price_seen
|
||||||
|
|
||||||
|
data = {"meta": meta, "daily": daily}
|
||||||
|
with open(out_path, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
print(f"Wrote {len(daily)} days to {out_path}")
|
||||||
|
PY
|
||||||
|
|
||||||
|
echo "Done. Last run: $(date)"
|
||||||
|
|||||||
Reference in New Issue
Block a user