- name
- alimama-cli
- description
- 万相台 AI 无界(one.alimama.com / 阿里妈妈 onebp)数据查询 + 单元关停 CLI。给 AI 代理一行命令拉取自家店铺的广告推广数据 — 涵盖"报表"(11 种历史复盘) + "推广"(3 种当前在投计划) + 单元/商品开关查询 + 账户余额 / 营销活动。查询类全只读;唯一写操作 promo-off(按宝贝ID关停在投单元)默认 dry-run,必须 --execute 才执行。触发场景:用户提到"万相台/阿里妈妈/广告投放/推广复盘/推广计划/onebp/alimama/广告效果/广告花费/ROI/计划报表/关键词推广/人群推广/货品全站推广/营销场景报表/广告数据/广告诊断/关停广告/关掉某商品"等。
- author
- rakel
- version
- 0.12.0
- tags
- ["taobao","alimama","advertising","ecommerce","cli"]
# alimama-cli — 万相台 AI 无界 数据查询 + 单元关停 CLI
## 一句话上手
```bash
~/.claude/skills/alimama-cli/scripts/alimama.sh doctor # 验证 cookie
~/.claude/skills/alimama-cli/scripts/alimama.sh charge-summary # 看昨天广告花了多少
```
## 适用人群
阿里妈妈广告主自己拉取自家店铺数据 + 关停广告。**查询类全只读**;**唯一的写操作是 `promo-off`(按宝贝ID关停在投单元),默认只列清单不执行,必须显式 `--execute` 才动**,且不调价/不删除/不新建。
## 前置条件
- macOS(已测试),Linux/Windows 理论可用
- macOS Chrome **已登录** https://one.alimama.com;Windows 首次运行会自动打开专用浏览器,登录一次即可
- 已装 `uv`(推荐)或 `pip install -r requirements.txt`
---
## 重要:模块结构(**别再搞混 "报表" vs "推广"**)
```
万相台 AI 无界
├─ 📊 报表(看历史数据复盘) → report-* 子命令 + charge-summary
└─ 🚀 推广(看当前在投的计划) → promo-* 子命令
```
| 维度 | 📊 报表 | 🚀 推广 |
|---|---|---|
| 时间 | **历史区间** | **当前快照** |
| 关心 | "昨天/上周花了多少、ROI 多少、谁转化好" | "现在哪些计划在跑、出价多少、日预算多少" |
| 接口 | `/report/query.json`(带 startTime/endTime)| `/campaign/horizontal/findPage.json`(无日期) |
| 用户问"昨天花了多少" | ✅ 用这个 | ❌ |
| 用户问"现在在投哪些关键词" | ❌ | ✅ 用这个 |
---
## 全部子命令(23 个,含 1 个写操作)
### 🔧 工具/账户类(5 个)
| 子命令 | 用途 |
|---|---|
| `doctor` | 检查 cookie / 登录态 |
| `account-balance` | 账户余额(实时) |
| `activity-list` | 营销活动列表 |
| `campaign-list` | 推广计划清单(仅 ID + 名字,无业务数据) |
| `api <path>` | 通用接口探测(debug 用,AI 代理一般不调) |
### 📊 报表类(11 个)—— 看历史数据
每个都接受:`--date YYYY-MM-DD --end-date YYYY-MM-DD --limit N --window 1|7|15 --raw --out file`
| 子命令 | 对应万相台页面 | 干嘛用 |
|---|---|---|
| `charge-summary` | 营销场景报表 | **总览**:各推广场景(关键词推广/人群推广)各花了多少 |
| `scene-summary` | 场景大盘(大屏) | **某场景大盘汇总**:展现量(adPv)/点击/花费/成交/ROI/加购/转化,默认过去7天,`--biz` 选场景 |
| `scene-daily` | 营销场景报表→分日详情 | **某场景按天**的展现/点击/花费/点击率/成交额/笔数/转化率/ROI 时序(含合计行),默认过去7天,`--biz` 选场景,`--window 1\|7\|15` 转化窗口 |
| `report-campaign` | 计划报表 | 按"每个推广计划"看花费 + ROI |
| `report-adgroup` | 单元报表 | 按"计划下的单元"看 |
| `report-keyword` | 关键词报表 | 按"每个关键词"看,找高 ROI 词加价/低 ROI 词砍 |
| `report-crowd` | 人群报表 | 按"每个定向人群"看转化率 |
| `report-item` | 商品报表 | 按"每个被推广的商品"看 |
| `report-creative` | 创意报表 | 按"每个广告图/视频/标题"看点击率 |
| `report-area` | 地域报表 | 按"客户城市"看 |
| `report-coupon` | 权益报表 | 优惠券效果 |
| `report-realtime` | 实时报表 | 今天到现在的实时数据(按小时) |
| `report-other` | 其他推广报表 | 杂项 |
### 🚀 推广类(3 个)—— 看当前在投
每个接受:`--limit N --page N --status start pause --raw --out file`(**不需要日期**)
| 子命令 | bizCode | 干嘛用 |
|---|---|---|
| `promo-wholesite` | onebpSite | 货品全站推广 - 当前在跑哪些计划 |
| `promo-keyword` | onebpSearch | 关键词推广 - 当前在跑哪些计划 |
| `promo-crowd` | onebpDisplay | 人群推广 - 当前在跑哪些计划 |
`promo-*` 还支持 `--item <宝贝ID>` 反查(这宝贝在哪个计划里推)。
**`promo-items --campaign <计划ID>`**:列出**一个计划里的全部商品 + 每个商品的开/关状态**(测款计划这类"一计划多商品"必用)。`--biz` 可限定玩法,默认自动搜全部。开关取自单元的 `onlineStatus`(1=开/0=关);标题为"商品已删除/下架"=广告开着但宝贝没了,该清理。
**`promo-units`**:把所有计划的**全部单元(=商品广告位)拉平成一张表**,相当于网页的"单元 Tab"。`--biz` 限定玩法(默认扫全部 3 种);`--item <宝贝ID>` 反查**某商品散落在哪些计划、各自开关**(这是"关掉某商品全部投放"的前置视图——一个商品常进多条计划,每条算一个独立单元各有开关);`--unit <单元ID>` 按单元ID精确定位一条单元。**`--item` 和 `--unit` 都走服务端过滤(不全量拉回来再筛),命中即停。**
---
## AI 代理决策指南(用户说什么 → 调用什么)
| 用户问 | 调用 |
|---|---|
| "看昨天广告花了多少" / "昨天的 ROI" | `charge-summary --date YYYY-MM-DD` |
| "哪些计划最赚钱" / "ROI 最高的计划" | `report-campaign --date X --end-date Y --limit 10` |
| "哪些关键词在浪费钱" | `report-keyword --date X --raw` 然后 jq 过滤 `charge>5 and alipayInshopAmt==0` |
| "现在关键词推广有多少计划在跑" | `promo-keyword` |
| "看货品全站推广现在的状况" | `promo-wholesite` |
| "宝贝 XXX 现在在哪个全站/关键词/人群计划里推" | `promo-wholesite --item XXX`(自动翻全部页反查,命中显示计划ID/预算/出价/状态) |
| "计划 XXX 里有哪些商品 / 哪个开哪个关" | `promo-items --campaign XXX` |
| "宝贝 XXX 散在哪些计划里 / 各自开关" | `promo-units --item XXX`(服务端过滤;三种玩法都准,含关键词推广) |
| "单元 XXX 是什么 / 看某个单元ID的信息" | `promo-units --unit XXX`(服务端精确定位,命中即停) |
| "把所有计划的单元拉平成一张表看" | `promo-units`(相当于网页"单元 Tab") |
| "把宝贝 XXX 的广告全关了" | ⚠️写:`promo-off --item XXX`(先看 dry-run 清单),确认后 `promo-off --item XXX --execute` |
| "人群/关键词推广的展现量/点击/花费/ROI 大盘" | `scene-summary [--biz crowd]`(默认过去7天,展现量=adPv) |
| "关键词推广这几天每天花费/ROI 怎么走的" / "某场景分日趋势" | `scene-daily --biz keyword --date X --end-date Y`(按天时序 + 合计行) |
| "看哪个人群转化好" | `report-crowd --date X --end-date Y` |
| "看每个商品的广告效果" | `report-item` |
| "看哪个城市出单多" | `report-area` |
| "看实时数据" | `report-realtime` |
| "账户还剩多少钱" | `account-balance` |
| 报错或验证环境 | `doctor` |
**默认 `--date` 是昨天**(避免今天数据不全)。
---
## 报表类输出 schema(喂给 LLM 分析时用)
`charge-summary` 输出格式化文本,加 `--raw` 拿 JSON:
```json
{
"data": {
"totalCharge": 12345.67,
"searchCharge": 6789.01,
"displayCharge": 5556.66,
"contentSceneCharge": 0,
"activitySceneCharge": 0,
"crowdSceneCharge": 0,
"shopSceneCharge": 0,
"itemSceneCharge": 0,
"siteSceneCharge": 0,
"agencySceneCharge": 0
}
}
```
`report-*` 输出格式:
```json
{
"data": {
"count": 57,
"totalData": {"charge": 1234.56, "alipayInshopAmt": 8888.88, "roi": 7.20},
"list": [
{
"campaignId": 0,
"promotionName": "<计划名>",
"charge": 100.00,
"alipayInshopAmt": 1000.00,
"roi": 10.00,
"click": 200,
"ctr": 0.040,
"ecpc": 0.50,
"cvr": 0.010,
"cartRate": 0.05,
"alipayInshopNum": 5
}
]
}
}
```
**完整指标 (queryFieldIn)**(v0.10 起含 `adPv` 展现量,报表输出已带"展现"列):
`adPv`(展现量) / `charge`(花费) / `click`(点击量) / `ctr`(点击率) / `ecpc`(平均点击花费) / `alipayInshopAmt`(成交金额) / `alipayInshopNum`(成交笔数) / `alipayDirNum`(直接成交单数) / `cartInshopNum`(加购数) / `cvr`(转化率) / `roi`(投产比) / `cartRate`(加购率) / `cartCost`(加购成本) / `colCartCost`(收藏加购成本) / `itemColCartCost`(商品收藏加购成本) / `inshopPotentialUvRate`(潜客率) / `newAlipayInshopUvRate`(新成交客户率)
不同 `report-X` 子命令的 row 里**名称字段不同**:
| 子命令 | 名称字段 |
|---|---|
| `report-campaign` | `promotionName` |
| `report-adgroup` | `adgroupName` |
| `report-keyword` | `originalWord` |
| `report-crowd` | `crowdName` |
| `report-item` | `itemTitle` |
| `report-creative` | `creativeName` |
| `report-area` | `provinceName` / `province` |
## 推广类输出 schema
`promo-*` 输出:
```json
{
"data": {
"count": 33,
"list": [
{
"campaignId": 0,
"campaignName": "<计划名>",
"bizCode": "onebpSearch",
"displayStatus": "start",
"dayBudget": 260.0,
"bidUnit": "平均点击成本${constraintValue}元",
"constraintValue": 0.27,
"bidTypeV2": "smart_bid",
"launchPeriodDisplayTime": "18:30-19:00",
"promotionType": "item",
"topStatus": true,
"gmtCreate": "2026-03-09 15:42:30"
}
]
}
}
```
判定状态:`displayStatus == "start"` 在投,`"pause"` 暂停。
### 宝贝 ID ↔ 计划 的对应(反查关键情报)
`findPage` 顶层的 `itemId` / `itemIdList` / `scopeItems` **恒为 null**,网页上能看到宝贝 ID 是因为请求体带了 `adgroupRequired:true`,服务端才回填单元:
```
计划行.adgroupList[] → 该计划下的所有单元(一计划可含多个单元)
计划行.adgroupList[i].material.materialId → 宝贝 ID(lastAdgroup.material 兜底)
计划行.adgroupList[i].material.title → 商品标题(被删/下架时为 null)
计划行.adgroupList[i].onlineStatus → 单元开关:1=投放中 / 0=未投放
```
`_promo_item()` 取第一个商品;`_promo_all_items()` 取全部单元 + 开关,供 `promo-items`/`promo-units` 用。CLI 已默认 `adgroupRequired:true`。
### 单元级接口(推荐用它做单元/商品查询)
**`POST /adgroup/horizontal/findPage.json?bizCode=<X>`** —— 扁平单元列表,每行一个商品广告位,**三种玩法都直接返回 `material.materialId`(宝贝ID)+ `material.title` + `onlineStatus` + `campaignId/campaignName`**。
请求体:`{bizCode, offset, pageSize, statusList:[start,pause,end], campaignId?, itemId?, adgroupId?}`。代码见 `fetch_all_adgroups()` + `_adgroup_unit()`,`promo-units`/`promo-items`/`promo-off` 都走它。
**三个服务端过滤参数(默认优先用,别再全量拉回客户端筛)**:
| body 参数 | 作用 | 实测 |
|---|---|---|
| `campaignId` | 只取某计划下的单元 | `promo-items` 用 |
| `itemId`(数字)| 只取某宝贝ID的单元 | **返回该商品散落各计划的全部单元**(验过 1 商品命中 15 单元),对 `promo-off` 关停安全;`promo-units --item`/`promo-off` 用 |
| `adgroupId`(数字)| 精确定位某个单元ID | count=1 命中即停;`promo-units --unit` 用 |
> ⚠️ 工作准则:**有 ID(计划/宝贝/单元)就走服务端过滤,命中即停;不要把全量(关键词单元上千)拉回客户端再 filter**——慢且易超时。仅当用户要"全表"才不带过滤。
**为什么不用"计划级 findPage + adgroupRequired"取单元**(踩过的坑):
| 玩法 | 计划级嵌套单元 material | 单元级接口 material | 备注 |
|---|---|---|---|
| 货品全站 onebpSite | ✅ 有宝贝ID | ✅ | 一计划=一商品 |
| 人群推广 onebpDisplay | ✅ 有宝贝ID | ✅ | 一计划=多商品;同商品常进多计划 |
| 关键词 onebpSearch | **❌ 恒 null** | ✅ 有宝贝ID | 计划级认不出商品,**必须走单元级接口** |
- 计划级 `adgroupRequired:true` 对关键词推广 **material 恒 null**,且单元巨多(单计划见过 266/1848 总),响应体大易超时 → **单元/商品查询一律用单元级接口**,不要再用 adgroupRequired 取单元。
- 单请求超时默认 30s(`ALIMAMA_TIMEOUT` 可覆盖);onebpSearch 服务端偏慢,`fetch_all_adgroups` 用 pageSize=50。
- `_promo_item()`/`_promo_all_items()`(计划级取单元)仅保留给货品全站/人群的快速取首图场景。
### 写接口:开关单元(`promo-off` 用)
**`POST /adgroup/updatePart.json?csrfId=<X>&bizCode=<biz>`** —— HAR 实测:
```
body: {"bizCode":"<biz>","adgroupList":[{"campaignId":<cid>,"adgroupId":<aid>,"displayStatus":"pause"}],"csrfId":"<X>"}
```
- `displayStatus`: `"pause"`=关(响应 `onlineStatus:0`) / `"start"`=开(`onlineStatus:1`)
- `adgroupList` 可一次传多个单元(同 bizCode 批量)
- 成功标志:响应 `data.errorCount == 0`
- `loginPointId` / `bx-v` 头:HAR 里有,但同源读接口不带也成 → **判定为可选埋点,CLI 省略**(首次实测确认)
- 代码:`set_adgroups_status()`;命令 `promo-off`(默认 dry-run,`--execute` 才真发)
View on GitHub