---
name: jd-keyword-analysis-skill
description: 京东商智行业关键词分析（覆盖 keywordQuery 与 hotKeywords 两个菜单）。输入任意关键词，拉取行业大盘概览、按天搜索趋势、相关热搜词与飙升词、流量竞争（二级类目/商品属性/价格带）、9 维搜索人群画像（性别/年龄/购买力/PLUS会员/京喜分/职业/城市等级/省份/省-市）、24 小时活跃度分布；也可按二级类目直接拉取行业热门关键词榜（最多 500 词，含排名变动与快车竞价参考价）用于挖词选品。输出 Swiss 国际风格单文件 HTML 报告并落盘原始 JSON。触发词：京东关键词分析、行业关键词、商智关键词、关键词洞察、搜索词分析、关键词人群画像、相关热搜词、相关飙升词、价格带分析、流量竞争分析、关键词选品、行业热词榜、热门关键词、挖词选词、keyword analysis。
license: MIT
metadata:
  author: AI Assistant
  version: 1.0.1
  created: 2026-09-22
  last_reviewed: 2026-09-22
  review_interval_days: 60
  python_dependencies:
    - requests
  dependencies:
    - url: https://jdsz.jd.com/squidweb/view/industry/keywordQuery.html
      name: 京东商智 · 行业关键词查询
      type: website
    - url: https://szgateway.jd.com/api/squidajax/paasf/v1/keywordQuery
      name: 商智关键词查询网关（33 个接口）
      type: api
---

# /jd-keyword-analysis — 京东商智行业关键词分析

## 0. 这个技能是干什么的

输入一个关键词（如「鞋子除臭」），输出这个词在京东行业大盘上的完整画像：

| 维度 | 回答什么问题 |
|---|---|
| 市场规模 | 这个词一个月多少人搜、点、买，成交多少钱 |
| 搜索趋势 | 整月走势怎么走，有没有起量 |
| 相关词 | 搜这个词的人还搜什么（热搜词 + 飙升词） |
| 流量竞争 | 这个词的流量被哪些类目、哪些商品属性、哪个价格带吃掉了 |
| 人群画像 | 搜这个词的人是谁：男女、年龄、购买力、会员等级、职业、城市 |
| 搜索时段 | 这个词的用户一天里什么时候在搜（24 小时分布） |
| 行业热词榜 | 整个类目的行业词库（最多 500 词），含排名变动与竞价参考。**不需要先有词**，给类目就能拉 |

**不做什么**：不查具体竞品商品、不查单店铺数据（那是 jd-shop-data-skill 的活）。

---

## 1. 前置条件（一次性配置）

需要两样东西，都放在 `config/凭证.local.json`：

1. **cookie** —— 商智登录态，一套全局共用
2. **endpoint_tokens** —— 34 组 `[user-mnp, user-mup, uuid]`，**按接口各一套**

> ⚠️ 商智网关对每个接口单独校验一组签名，跨接口复用会直接返回
> `code -407 不安全的请求`。签名不绑定请求体 —— 配一次可查任意关键词 / 月份。
> 背景详见 `references/config-guide.md`。

### 1.1 用户会把这两样东西交给你

用户照着 `抓包指南.html` 抓包，然后把结果发给你：

| 他给什么 | 长什么样 |
|---|---|
| **抓取结果** | 一段 JSON：`{"endpoint_tokens": {"keywordQuery/xxx/yyy": ["mnp","mup","uuid"], ...}, "pin": "..."}` |
| **cURL** | 从商智 Network 面板 Copy as cURL 出来的一整段命令，cookie 藏在 `-H 'cookie: ...'` 里 |

他可能只给其中一样；也可能粘得很乱（带说明文字、包在 markdown 代码块里、
或者把两样混在一条消息里）。**这些情况都要能处理，不要让他重新整理。**

### 1.2 你要做的四件事

**① 从 cURL 里取 cookie**（用户给了 cURL 才做）

```python
import re
m = (re.search(r"-H\s+['\"]cookie:\s*(.+?)['\"]", text, re.I | re.S)
     or re.search(r"--header\s+['\"]cookie:\s*(.+?)['\"]", text, re.I | re.S))
cookie = m.group(1).strip() if m else ""
```

**② 写入凭证** —— 用 `--import-tokens`（会自动合并 + 自动体检）

```bash
# 推荐：从标准输入读，不落临时文件
echo '<抓取结果 JSON>' | python scripts/run.py --import-tokens - --cookie "<cookie>"

# 或先存成文件
python scripts/run.py --import-tokens tokens.json --cookie "<cookie>"
```

合并语义：只更新本次出现的接口，**已有的 cookie 和其它接口签名不受影响**。
所以用户分两次抓、或者过几天补抓几个，都可以直接再导一次。

**③ 判断结果并如实告诉用户**

| 输出里看到 | 含义 | 你要说 |
|---|---|---|
| `合计 34` + `体检 ✅ 通过` | 成功 | 可以用了，并给出下一步命令 |
| `合计` 少于 34 | 有接口没抓到 | 把「跳过 N 项」里的接口名告诉他，让他回商智补抓 |
| `体检 ❌`，报 -407 | cookie 或签名过期 | 让他重新登录商智再抓一次 |
| cookie 没填 | 少了 cURL | 让他补一段 cURL |

**④ 告诉他下一步能跑什么**

```bash
python scripts/run.py --hot-cate2 16753                      # 行业词库
python scripts/run.py --keyword "鞋子除臭" --month 2026-08    # 单词分析
```

### 1.3 AI 不在场时的手工方式

```bash
python scripts/run.py --import-clipboard    # 从剪贴板导入（用户先执行 __jdKwImport()）
python scripts/run.py --list                # 看已配了哪些（应显示 34 个）
python scripts/run.py --check               # 验证凭证是否可用
```

模板 `config/凭证.example.json` 已列好全部 34 项的 key（值为空占位），
也可以照它手工填。

---

## 2. 怎么用

```bash
# 单关键词全量分析（33 个接口）
python scripts/run.py --keyword "鞋子除臭" --month 2026-08

# 带目标类目校验（推荐）：检查这个词的流量是不是真的落在你的类目上
python scripts/run.py --keyword "鸡皮" --month 2026-08 --target-cate "身体护理"

# 只看某一块
python scripts/run.py --keyword "鞋子除臭" --month 2026-08 --only crowd
python scripts/run.py --keyword "鞋子除臭" --month 2026-08 --only related

# 批量（文件每行一个词，# 开头为注释）
python scripts/run.py --batch keywords.txt --month 2026-08

# 行业热词榜：按二级类目拉，不需要先有词（16753 = 身体护理）
python scripts/run.py --hot-cate2 16753
python scripts/run.py --hot-cate2 16753 --hot-days 7 --hot-size 500

# 合并：关键词分析 + 热词榜出在同一份报告里
python scripts/run.py --keyword "鞋子除臭" --month 2026-08 --hot-cate2 16753

# 节流：默认请求间隔 1.2s，可调
python scripts/run.py --keyword "凉席" --month 2026-08 --interval 2
```

产出三份文件到 `out/`：

| 文件 | 内容 |
|---|---|
| `{关键词}_{月份}.json` | 全部原始响应，可回溯，接口改版时可对比 |
| `{关键词}_{月份}.report.json` | 结构化分析结果，供二次加工 |
| `{关键词}_{月份}.html` | Swiss 风格可视化报告，可直接发群 |

---

## 3. 关键机制（改代码前必读）

### 3.1 签名按接口绑定，不能跨接口复用

`user-mnp` / `user-mup` / `uuid` 三个头是一个整体，**每个接口一套**。实测：

| 用例 | 结果 |
|---|---|
| 各接口用自己那套签名 | ✅ 全部通过 |
| 用 overview 的签名去打 tendency | ❌ -407 |
| 只把三个头中的一个换成新生成的值 | ❌ -407 |
| 三个头全部本地随机生成 | ❌ -407 |

两条推论，都很重要：

- **不能本地生成**：这三个头是服务端签发的，`user-mup` 虽然长得像毫秒时间戳，但服务端并不接受自己造的值。
- **签名与请求体无关**：换关键词、换月份、改 metrics 全部实测可用。所以 34 组签名配一次，能查**任意关键词**。

### 3.2 两套渠道口径，数字不能混着用

| 取数范围 | chanType | 口径 |
|---|---|---|
| 概览 / 相关词 / 流量-类目 / 流量-价格 | `-999` | 全渠道 |
| 流量-属性 / 全部人群接口 | `10000101` | 单渠道（具体端待确认） |

人群画像是**单渠道口径**，不能和概览的全渠道 UV 直接做除法。

### 3.3 数据形态：区间 vs 精确值

| 返回形态 | 出现在 | 值的样子 |
|---|---|---|
| 区间 | 概览、趋势、人群 histogram、价格带、流量-属性 | `{median: 7000, range: "6000.0 ~ 8000.0"}` |
| 精确值 | 人群 table、流量-类目 | `0.3960308710033076` |

概览的 UV / GMV / 订单数都是**区间**，报告里取中位数仅作参考，不能当准确数对外引用。
人群分布是精确值，可以放心用。

### 3.4 返回码的位置

成功判断看 `body.header.code == 0`，**不是**顶层 `code`。`-407` 表示鉴权失败，
最可能是签名过期，需要按 §1 重抓。

### 3.5 词义纯度 —— 分析任何词之前先做这一步

**`flow/category`（类目分流）不只用来「看竞争格局」，它还是「验词义纯度」的工具。**

实测案例：查「鸡皮」这个词，类目分流是

| 二级类目 | 点击占比 |
|---|---|
| **鸡鸭禽肉** | **55% ~ 60%** |
| 身体护理 | 25% ~ 30% |
| 肉类零食 | 10% ~ 15% |

因为「鸡皮」既可以是「鸡皮肤（毛周角化）」的简称，也可以是「鸡的皮」这个生鲜食材。
**这个词的 UV / 价格带 / 人群指标全被食品流量污染，直接当护肤需求读会得出完全错误的结论。**

报告顶部现在会自动给出「词义纯度」提示条，分四档：

| 档位 | 含义 |
|---|---|
| 通过 | 词义集中，指标可直接用 |
| 待确认 | 没指定目标类目，只提示 Top1 是谁 |
| 需注意 | 目标类目占比 50%~75%，量级被高估 / 或类目名没匹配上 |
| 有风险 | 目标类目占比 < 50%，指标已被污染 |

用 `--target-cate "你的二级类目名"` 可自动校验。**类目名要写报告里出现的准确名称**——
写简称会匹配到占比极小的长尾类目，此时程序会提示"大概率不是你要的类目"并列出实际类目名。

**更根本的办法：模糊词换成精准长尾词。** 实测「鸡皮」的相关词里，
`鸡皮肤疙瘩毛囊角化专用去除大腿胳膊手臂`（uv 4,000~6,000）量级比母词「鸡皮」（2,000~4,000）还大
——真需求藏在长尾词里。

---

## 4. 代码结构与扩展

```
scripts/
├── run.py            命令行入口（--import-clipboard / --import-tokens / --check / --list / --keyword / --batch / --only / --hot-cate2）
├── keyword_api.py    ★ 34 个接口 → 7 个方法，底层统一处理 header / 节流 / 错误
├── analyze.py        原始 JSON → 业务结论
├── report_html.py    业务结论 → HTML
├── config_manager.py 凭证读写 + 完整性校验 + 体检 + import_tokens（合并导入）
└── capture_tokens.js 浏览器端签名抓取脚本（含 __jdKwImport 一键复制）

抓包指南.html          纯静态抓包步骤页 —— 双击就能打开，不需要联网、不需要起服务。
                      使用者照着它抓包，然后把结果交给你配置（见 §1.1 / §1.2）
```

`keyword_api.py` 的接口→方法映射：

| 方法 | 覆盖接口 | 切换参数 |
|---|---|---|
| `overview()` | searchOverview/overview | — |
| `tendency()` | searchOverview/tendency | `metrics` |
| `related()` | related/hot、related/soar | `kind="hot"｜"soar"` |
| `flow()` | flow/category、flow/attr、flow/price | `dim="category"｜"attr"｜"price"` |
| `crowd()` | 25 个人群接口 | `dim`（9 个）× `view`（各自声明的视图；province 系列只有 summary/table） |
| `activity_trend()` | crowdActivity/trend | 无参数，返回 hour 0~23 的活跃度 |
| `hot_keyword_list()` | hotKeywords/searchKeywordHotList/table | `cate2` 二级类目 + `start`/`end` 日期区间 |

**增加新接口**：在 `config/凭证.local.json` 的 `endpoint_tokens` 里加一条，key 用
**完整路径**（如 `keywordQuery/searchOverview/overview`），再在 `keyword_api.py` 加一个业务方法即可，
底层 `call()` 会从路径自动推导 `menucode` / `referer` / `model` 三个头，并处理签名和错误。

---

## 5. 已知边界

| 情况 | 影响 |
|---|---|
| `crowdProvince/histogram`、`crowdProvinceCity/histogram` **不存在** | 这两个维度没有独立的图表视图 —— 实测在页面上切换到图表不会发出 histogram 请求。代码里由 `CROWD_DIMS[dim]["views"]` 声明只跑 summary + table，所以单关键词全量是 **33 次请求** |
| `crowdActivity` 的兄弟接口未确认 | 目前只有 `trend`（24 小时活跃度分布），是否还有 summary / table 未知 |
| `lpr` 字段口径未确认 | 报告里只作"对比值"展示，不下结论 |
| 人群表 `uvValue`（报告中列名「指数」）口径未确认 | 仅供参考，不作判断依据 |
| 未抓到竞品商品列表接口 | 知道哪些词热、哪些词在涨，但不知道具体是哪些商品在吃这些词 |
| `hotKeywords` 页面的其他 Tab 未确认 | 目前只有榜单一个接口；是否有历史趋势、类目切换之外的维度未知 |
| `maxScore`、`keywordType` 含义未确认 | 解析时略过，不影响主流程 |

补抓方法：在商智关键词查询页面点开对应位置，用 `capture_tokens.js` 重新收集，替换
`endpoint_tokens` 即可。

---

## 6. 常见问题

| 现象 | 原因 / 处理 |
|---|---|
| 全部接口 -407 | cookie 或整批签名过期，按 §1 重新抓一次 |
| 个别接口 -407 | 该接口签名失效，单独补抓那一个（重复导入会合并） |
| 返回"缺有效签名" | `endpoint_tokens` 里这一项为空，或 key 写法不对（必须是完整路径），按 §1 补抓 |
| Excel 粘贴后 user_mup 变 1.79E+12 | 单元格被当数字，先设文本格式再粘贴；`config_manager` 会校验并提示 |
| 请求变慢或被拒 | 调大 `--interval`，单关键词全量是 33 次请求，批量时按倍数增加 |

详细规格见 `references/`：
`api-spec.md`（34 接口逐字段）、`config-guide.md`（抓包 SOP）、
`metric-glossary.md`（指标口径与置信度）。

---

## 7. 打包分发（维护者用）

`config/凭证.local.json` 含真实 cookie 与 34 组签名，**绝不能进分发包**。

⚠️ **不要用 skill-creator 的 `package_skill.py` 打包这个 skill。**
实测它不读 `.gitignore`，会把目录下所有文件全量打进去 —— 凭证和 `out/` 运行产物
都会中招（2026-09-22 真实泄漏过一次）。

用 `_dev/pack_skill.py`（在开发目录，不在本 skill 内），一条命令出两个包并自动校验：

```bash
python _dev/pack_skill.py          # 打包 + 校验
python _dev/pack_skill.py --check  # 只校验已有包
```

| 产出 | 用途 |
|---|---|
| `..._可分发.zip` | 不含凭证，可外发 |
| `..._含凭证-勿外传.zip` | 含凭证，自用 |

校验项：抓取教程在不在、配置模板在不在、凭证有没有泄漏、有没有混入 `out/` 或 `.pyc`。

**外发前建议做一次新用户验证**：把可分发包解压到临时目录，照 `开始使用.md` 走一遍，
看有没有卡住的地方。文件齐不齐是静态的，能不能用是动态的 —— 这一步实测出过三个缺陷。


## 2026-09-29 修复说明

v1.0.1：修复趋势谷值对零的处理，零值不再被误当成缺失值。
