From a1c8770e1e83f1f4eac83b68f671c4ce05f6efc2 Mon Sep 17 00:00:00 2001 From: chii Date: Fri, 7 Aug 2026 11:52:55 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E7=A7=BB=E4=BA=A4=20playbook=20?= =?UTF-8?q?=E4=B8=8E=20H10=20=E9=9C=80=E6=B1=82=E8=8D=89=E7=A8=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 sif 提炼的抓取微服务范式作为开发建议入库,并标明本仓移交其他团队落实开发;不含凭据与实现代码。 Co-authored-by: Cursor --- README.md | 20 ++- docs/HANDOVER.md | 26 +++ docs/requirements-h10.md | 56 +++++++ docs/scraper-service-playbook.md | 267 +++++++++++++++++++++++++++++++ 4 files changed, 368 insertions(+), 1 deletion(-) create mode 100644 docs/HANDOVER.md create mode 100644 docs/requirements-h10.md create mode 100644 docs/scraper-service-playbook.md diff --git a/README.md b/README.md index 0ad3844..7d6239b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,21 @@ # amazon-h10-api -H10抓取微服务 \ No newline at end of file +Helium 10(H10)相关数据抓取微服务 — **移交中**。 + +## 重要说明 + +| 项 | 说明 | +|----|------| +| 仓库状态 | **方法论与需求移交**;业务代码尚未实现 | +| 接手方 | 由其他开发团队落实编码、逆向、部署与交付 | +| Playbook | [`docs/scraper-service-playbook.md`](docs/scraper-service-playbook.md) — **开发建议**,非强制规范 | +| 移交说明 | [`docs/HANDOVER.md`](docs/HANDOVER.md) | +| 业务需求 | [`docs/requirements-h10.md`](docs/requirements-h10.md) | + +对标参考(已上线同类服务):`amazon-sif-api`、`amazon-keepa-api`。 + +## 快速入口 + +1. 读 [`docs/HANDOVER.md`](docs/HANDOVER.md) +2. 读 [`docs/scraper-service-playbook.md`](docs/scraper-service-playbook.md)(建议范式) +3. 读 [`docs/requirements-h10.md`](docs/requirements-h10.md)(H10 功能范围) diff --git a/docs/HANDOVER.md b/docs/HANDOVER.md new file mode 100644 index 0000000..a96d258 --- /dev/null +++ b/docs/HANDOVER.md @@ -0,0 +1,26 @@ +# 仓库移交说明 + +## 状态 + +本仓库(`amazon-h10-api`)当前为**需求与方法论移交包**,**尚未实现抓取微服务代码**。 + +后续编码、浏览器逆向、契约沉淀、部署与冒烟,由**接手开发团队**落实。 + +## 文档清单 + +| 文档 | 性质 | 说明 | +|------|------|------| +| [scraper-service-playbook.md](./scraper-service-playbook.md) | **开发建议** | 从 sif 提炼的通用构建范式;非强制规范 | +| [requirements-h10.md](./requirements-h10.md) | 业务需求草稿 | H10 关键词反查 / 排名监控 / 排名表格抓取 | + +## 建议起步顺序(仅建议) + +1. 阅读 playbook(尤其 P1–P3、§4.1 是否引入 PG)。 +2. 按 `requirements-h10.md` 做 P1 范围确认(首个交付域建议:产品词表反查)。 +3. 对 [Helium 10 Members](https://members.helium10.com/) 做 P2 浏览器逆向,产出 `*-contract.md`(**凭据勿入库**)。 +4. 再按 playbook P3–P7 实现与交付。 + +## 凭据与安全 + +- 目标站账号 / API Key / 会话 token:**不得提交进 Git**。 +- 交接凭据请走团队既有密钥渠道(secret / 密码库),勿写进本目录 markdown。 diff --git a/docs/requirements-h10.md b/docs/requirements-h10.md new file mode 100644 index 0000000..8177bbb --- /dev/null +++ b/docs/requirements-h10.md @@ -0,0 +1,56 @@ +# H10 关键词数据反查与导出 — 需求草稿 + +> **性质**:业务需求说明(草稿),供接手团队澄清与排期。 +> **目标站**:https://members.helium10.com/ +> **凭据**:向移交方索取,**禁止写入本仓库**。 + +## 功能概览 + +| # | 能力 | 说明 | +|---|------|------| +| 1 | 词表反查 | 按顺序:先产品词表反查,再全量词表反查;ASIN 由调用方/用户提供 | +| 2 | 排名监控录入 | 将 ASIN + 关键词加入 H10 排名监控;多组则循环添加 | +| 3 | 排名表格抓取 | 与词表反查独立,单独执行 | + +--- + +## 1. 词表反查(顺序执行) + +本品 ASIN、竞品 ASIN **由用户自行提供**。 + +### 1.1 产品词表反查 + +1. 进入 Helium 10 对应功能页,按产品词表反查流程操作。 +2. 输入本品 ASIN。 +3. 完成反查后导出。 +4. **导出名**:`{本品ASIN}+反查词表`。 + +### 1.2 全量词表反查 + +在 1.1 完成后的界面继续: + +1. 在本品 ASIN 基础上输入竞品 ASIN。 +2. 按全量词表反查流程操作并导出。 +3. **导出名**:`{本品ASIN}+全量词表`。 + +--- + +## 2. 排名监控录入 + +- 输入的 ASIN、关键词均由用户提供。 +- 若提供多组「ASIN ↔ 关键词」,则**重复执行添加步骤**,直到全部录入完毕。 + +--- + +## 3. 排名表格抓取 + +- 与「词表反查」区分开,**单独任务**执行。 +- 进入对应页面后按既定 UI 流程抓取排名表格数据。 + +--- + +## 实现提示(对接 playbook) + +- 优先用浏览器逆向还原 HTTP 契约,再 HTTP 直连取数(见 [scraper-service-playbook.md](./scraper-service-playbook.md))。 +- 若导出仅为浏览器下载文件,需在契约中明确:是直链下载、异步任务轮询,还是必须走浏览器下载流。 +- 开放对外 API 前须确认 Helium 10 侧计费 / 风控 / ToS 边界。 diff --git a/docs/scraper-service-playbook.md b/docs/scraper-service-playbook.md new file mode 100644 index 0000000..11247ab --- /dev/null +++ b/docs/scraper-service-playbook.md @@ -0,0 +1,267 @@ +# 数据抓取微服务构建通用范式(Playbook) + +> **文档性质:开发建议(非强制规范、非已落地实现)** +> +> - 本文供接手 `amazon-h10-api` 的开发团队参考,说明「同类抓取微服务」推荐怎么做。 +> - **本仓当前未实现业务代码**;落地开发、契约逆向、部署与运维由接手团队负责。 +> - 内容提炼自 `amazon-sif-api` 的真实构建过程,属可复用方法论,可按 H10 目标站实际情况裁剪,不必逐字照搬。 +> - 对标蓝本:`amazon-sif-api` / `amazon-keepa-api`(轻量、默认无 PG、api + auth + worker + mq)。 + +> 适用:目标是某个**有登录态的 SaaS/数据平台**,要把它已聚合的数据,以**自有 REST API** 稳定、低成本地对外提供。 + +--- + +## 0. 一句话范式 + +> **用浏览器把"人能看到的数据"逆向成"机器能调的接口契约",再用一套无状态取数 + 集中式会话 + 队列派发的微服务把它工程化、可运维地交付。** + +核心信条: +1. **浏览器只用来"探路"和"拿钥匙",不用来"搬货"。** 登录/拿 token 用真浏览器;批量取数用 HTTP 直连(快、省、稳)。 +2. **先抓契约,再写代码。** 没摸清请求/响应结构前不写业务逻辑。 +3. **会话集中、取数无状态、派发异步。** 三者解耦,才能横向扩展又不互相拖垮。 +4. **每个域(domain)闭环交付:探索→实现→冒烟→真实样本→文档。** 不堆半成品。 + +--- + +## 1. 阶段总览 + +| 阶段 | 目标 | 关键产出 | +|------|------|---------| +| P1 需求澄清 | 定边界、定形态、定蓝本 | 需求共识、对标项目、首个交付域 | +| P2 浏览器逆向 | 把页面行为还原成 HTTP 接口契约 | `*-contract.md`(登录+各数据接口) | +| P3 架构设计 | 定服务拆分、会话/鉴权/扩展策略 | `design.md`、里程碑、风险清单 | +| P4 编码实现 | 按域实现取数+归一化+对外路由 | 三服务代码 | +| P5 部署 | 按目标环境规范上线 | 部署脚本、stack/compose | +| P6 冒烟+取样 | 真实数据验证每个端点 | `samples/*.json` | +| P7 文档交付 | 给接入方可直接用的文档 | `api.md`(脱敏) | + +> 后续每新增一个数据域,只重复 **P2(局部) → P4 → P6 → P7**,架构不动。 + +--- + +## 2. P1 · 需求澄清 + +**目标**:把"做个 XX 数据 API"收敛成可执行的最小闭环。 + +必须问清的 4 件事(缺一不可): +- **数据来源形态**:登录后聚合页?官方 API?纯爬 HTML?→ 决定逆向难度与合规风险。 +- **对外形态**:REST / MCP / GraphQL?响应结构对齐谁?→ 本项目选「REST 为主,结构对齐目标平台的 MCP 工具语义」,让下游迁移成本最低。 +- **首个交付域**:别想一次做全。挑一个**高价值 + 可独立验证**的域先打通(本项目=反查关键词)。 +- **架构蓝本与体量**:找一个同类已上线项目对标(本项目=`amazon-keepa-api`),明确"要多轻"。避免过度设计。 + +**决策原则**:能用「合理默认 + 事后说明」就别反复追问;只有**范围/破坏性/不可逆**的点才必须确认。 + +--- + +## 3. P2 · 浏览器逆向(范式的灵魂) + +**目标**:把"人在页面上点一下看到的数据",还原成一条可复现的 HTTP 调用(URL + headers + body + 响应结构)。 + +### 3.1 方法 +1. **真人操作 + 拦截网络**:用浏览器自动化打开目标页,注入网络拦截器(或开 DevTools/CDP),触发一次目标操作,捕获 `XHR/fetch`。 +2. **抓三类东西**: + - **鉴权机制**:token 在哪(localStorage/cookie/header)?格式(JWT?)?有无设备指纹/签名参数?过期时间? + - **公共参数**:每个请求都带的 query/header(时间戳、站点、`_m` 指纹…)。 + - **业务接口**:路径、方法、请求体字段、响应外层与 `data` 结构。 +3. **分域归档**:把接口按数据域分类记进 `*-contract.md`,每个接口标注「对应哪个对外功能」「是否计费」「关键返回字段」。 +4. **标注噪音**:UI 辅助接口(弹窗、埋点、文案)明确标记"无需复刻",避免后人误抓。 + +### 3.2 本项目实证 +- 发现鉴权 = `localStorage.token`(JWT, `exp`≈7天) 放进 `authorization` 头(**无 `Bearer` 前缀**)。 +- 发现每个请求带设备指纹 `_m`(来自 `localStorage._murmur`)——**跨进程复用 token 必须连指纹一起带**,否则风控。 +- 找到一个**不计费的探针接口**(`/api/user/sys/info`)用于校验会话有效性。 +- 把"反查/流量/概览/广告"四域接口结构全部记入契约文档。 + +### 3.3 坑 +- **入口不明 / 计费不清的功能先别碰**:本项目"市场需求/竞争"域因入口是耗积分的增值功能且契约未实测,**主动顺延**而非硬抓——避免在不确定处耗时跑偏。 +- **逆向到的接口要立刻人工核对一次**:字段名、计费字段(`consumeIntegral`)、分页规则。 + +### 3.4 产出 +`docs/*-contract.md`:逆向契约(**只记结构,不记真实凭据**)。 + +--- + +## 4. P3 · 架构设计(四服务范式) + +**目标**:一套能横向扩展、会话自愈、低成本的拆分。 + +``` + ┌───────────┐ REST(+API Key) ┌──────────────┐ + 调用方 →│ api │───────────────────→│ account 池 │ + │ 网关/缓存 │ └──────────────┘ + └─────┬─────┘ + │ 任务(MQ RPC) + ┌─────▼─────┐ 按需要会话 ┌───────────┐ 无头登录 ┌────────┐ + │ worker │──────────────→│ auth │──────────→│ 目标站 │ + │ 取数+归一化 │ (HTTP直连取数)└───────────┘ 探针/重登 └────────┘ + └───────────┘ +``` + +| 服务 | 职责 | 为什么独立 | +|------|------|-----------| +| **api(网关)** | REST 路由、API Key 鉴权、账号池轮询、任务派发、TTL 缓存、运维 UI | 对外唯一入口,无业务取数逻辑,便于加缓存/限流/鉴权 | +| **auth(会话)** | 无头浏览器登录、token/指纹/cookie 落盘、有效性探针、巡检、**单飞重登** | 登录是最重、最易触发风控的环节,集中管理 + 串行化 | +| **worker(取数)** | 消费任务 → HTTP 直连取数 → 归一化;遇鉴权失败标记失效并重试一次 | **无状态**,可任意多副本横向扩展吞吐 | +| **mq(队列)** | api↔worker 的异步 RPC | 解耦派发与执行,削峰、天然负载均衡 | + +### 设计要点(通用) +- **会话三道校验**:①取数前本地预检(零成本)②后台巡检(探针接口,不计费)③取数遇鉴权失败被动兜底 → 重登重试。 +- **单飞重登**:同账号重登加锁,并发请求只触发一次登录,其余复用新 token——**防惊群触发风控**。 +- **设备指纹随 token 走**:复用 token 时必须带登录时的指纹。 +- **轻量优先**:文件会话 + 进程内 TTL 缓存,**默认无数据库**(对标蓝本体量,见 §4.1)。 +- **凭据外置**:账号/密码走 `config.json`(不入库),对外 key 走环境变量/secret。 +- 产出:`design.md`(含里程碑 + 风险清单:token 并发、指纹绑定、计费、风控、schema 漂移、合规、**PG 连接预算**)。 + +### 4.1 存储选型与 PostgreSQL 连接数(prod 实证) + +> **结论先行**:与 sif / keepa / listing-scraper 同类的「轻量数据获取微服务」**默认不需要 PostgreSQL**,也**不需要 pgbouncer**。只有业务必须落库、或要做跨请求持久化查询时,才引入 PG,且**必须做连接预算**。 + +#### prod 同类服务调查(swarm-mgr3,排除 lsvdaas) + +| 服务 | 用 PG? | 副本 | pgbouncer? | 连接风险 | +|------|---------|------|-------------|----------| +| **sif** | 否 | api 1 + worker 3 + auth 1 | — | 无 | +| **keepa** | 否 | api 1 + worker 3 + auth 1 | — | 无 | +| **listing-scraper** | 否 | api 1 + worker 3 | — | 无 | +| **jiimore** | 否 | api 1 + worker 3 + auth 1 | — | 无 | +| **voc-analysis** | 是 | api 1 + worker 1 | 否(直连) | 低(副本少,采样时连接≈0) | +| **onesvm-asinwarehouse** | 是 | backend 1 + proxy 1 + worker 10 | 有 stack 但未接线 | **中高**(理论峰值≈72,当前≈20/200) | + +共享 PG(`postgres_db`)`max_connections=200`,采样时总连接约 55,**未见 `too many connections`**。 + +#### 何时不用 PG(推荐默认) + +满足以下多数条件时,坚持「无 DB」范式(本项目的 sif / keepa 已验证): + +- 数据可**实时从源站聚合**取回,无需本地持久化查询。 +- 会话/配置用**文件**即可(`config.json` + `sessions/*.json`)。 +- 去重用**进程内 TTL 缓存**或 MQ 天然串行即可。 +- 不需要复杂报表、历史回溯、跨 ASIN 关联查询。 + +**收益**:零 PG 连接占用、部署简单、worker 随意扩副本无连接压力。 + +#### 何时需要 PG + 怎么做才不爆连接 + +引入 PG 前必须算清**连接预算**: + +``` +集群峰值连接 ≈ Σ (每服务副本数 × 每副本最大连接数) +每副本最大连接数 = pool_size + max_overflow # SQLAlchemy + 或 max_size # asyncpg +``` + +**ASW 反例(prod 实测)**: + +| 组件 | 副本 | 每副本池上限 | 集群峰值 | +|------|------|--------------|----------| +| backend | 1 | 30 (10+20) | 30 | +| proxy_manager | 1 | 8 | 8 | +| listing worker | 4 | 4 | 16 | +| reviews worker | 6 | 3 | 18 | +| **合计** | **12** | | **≈72** | + +平台虽有 `asw-pgbouncer`(`:6432`),但 ASW 服务**全部直连 `postgres_db:5432`**,pgbouncer 未接线——这是典型「建了没用」的教训。 + +#### 引入 PG 的硬性规范 + +1. **多副本 worker 必须经 pgbouncer**,禁止每个 worker 进程各自开大池直连 PG。 +2. **连接池要小**:worker 侧 `pool_size` 建议 2–5;`max_overflow` 0–3;宁可排队不要占连接。 +3. **部署前做预算表**:写入 `design.md`,标明「副本数 × 池大小 = 峰值」,确认 `< PG max_connections × 30%`(留余量给其他服务)。 +4. **优先异步单连接**:轻量写入/状态表可用「单连接 + 队列」而非每请求开连接。 +5. **监控**:接入后观察 `pg_stat_activity` 按库/按应用计数;日志搜 `too many connections`。 + +#### 决策树(简版) + +``` +需要跨请求持久化查询 / 历史落库? +├─ 否 → 文件会话 + MQ + 进程缓存(sif/keepa 范式)✅ +└─ 是 → 算连接预算 + ├─ 峰值 < 20 且单副本 → 可直连,小池(pool≤5) + └─ 多副本 worker / 峰值 > 20 → 必须 pgbouncer + 小池 +``` + +--- + +## 5. P4 · 编码实现(按域可扩展) + +**目标**:让"加一个数据域"成为填空题,而不是改架构。 + +落地模式(本项目验证有效): +- **worker 侧**:一个通用 `_request()`(统一拼公共参数、塞鉴权头、判 `code`、识别鉴权错误抛 `AuthError`)+ 每个域一个 `fetch_xxx()` + 一个 `normalize_xxx()`;`main.py` 用 `OPS = {op: (fetcher, normalizer)}` 表分发。 +- **api 侧**:一个共享 `_dispatch(op, params, cache_key, ...)`(查缓存→选账号→MQ RPC→包 `meta`)+ 每个域一个瘦路由。 +- **归一化原则**:拿不准全部字段时,**先"透传 data + 轻量字段映射"**,保证冒烟能跑、文档有内容,再按真实返回逐步精修字段(本项目 traffic-trend 就是先透传、看到真实键名后再对齐 `totalScore/nfScore…`)。 +- **错误语义化**:鉴权类错误 → 触发重登重试;其余 → 明确 502/504/503。 + +> 扩展一个域的改动量 = 2 个函数(fetch+normalize)+ 1 条 OPS + 1 个路由。架构零改动。 + +--- + +## 6. P5 · 部署(按目标环境规范) + +**目标**:一条命令可复现地上线到目标环境。 + +- **遵守目标环境规范**:本项目按 onesvm-ops——compose/stack、amd64、指定 registry、`placement.constraints` 固定节点、资源限制、`docker secret` 装敏感信息、`--resolve-image never`。 +- **部署脚本要点(踩坑沉淀)**: + - 用**用户可写目录**同步源码(别假设 `/opt` 有权限)。 + - `scp` 前先 `mkdir -p` 远端目录。 + - 端口冲突先探测、可配置(本项目 8080→8088)。 + - `docker service update` 会换容器,**之后要重取容器 ID**再 exec。 + - **同名 tag 复用时**,worker 需 `--force` 才会真正滚动到新镜像(否则跑旧代码——本项目实测踩到)。 +- 产出:`scripts/deploy-xx.sh` + `deploy/stack.yml` / `docker-compose.yml`。 + +--- + +## 7. P6 · 冒烟 + 取真实样本 + +**目标**:每个对外端点用真实请求验证,并把返回存成示例数据。 + +- **逐端点单独冒烟**,打印关键字段 + `meta`(延迟、计费、是否命中缓存)。 +- **省成本**:注意计费额度,能一次验证就别重复;相同参数靠缓存。 +- **把真实返回落盘** `docs/samples/*.json`——它既是回归基线,又是文档示例的事实来源(文档示例必须来自真实数据,不杜撰)。 +- 冒烟暴露的字段不匹配 → 回 P4 精修归一化 → 重新取样。 + +--- + +## 8. P7 · 文档交付(给接入方) + +**目标**:同事拿到就能调。 + +`api.md` 必含: +- 接入信息(base URL、鉴权方式、健康检查、在线 `/docs`)。 +- 通用约定(公共参数、`meta` 结构、缓存、错误码)。 +- **每个端点**:参数表 + 真实 curl + **真实裁剪响应** + 字段要点。 +- **开放边界**:明确哪些开放(如"会员权益内、不计费、可无限查")、哪些关闭及原因(如"耗积分功能一律关闭")——让接入方不踩计费雷。 + +### 安全红线(务必) +- **真实 key / 账号 / 手机号绝不进仓库**。文档用占位符(`$API_KEY` / "向维护方索取")。 +- 若敏感信息**已误提交**:移除 + **改写历史**(`reset --soft` 重做提交) + `force-with-lease` 覆盖远程 + 本地 `reflog expire && gc`,并 `git log -S ''` 验证为空。 +- 误暴露过的凭据,最稳妥是**轮换**而非仅删除。 + +--- + +## 9. 复用检查清单(开新项目照着走) + +``` +[ ] P1 需求:来源形态 / 对外形态 / 首个域 / 对标蓝本+体量 都已确认 +[ ] P2 逆向:鉴权机制 / 公共参数 / 指纹 / 不计费探针 / 各域契约 已记入 *-contract.md +[ ] P2 逆向:噪音接口已标注;入口不明或计费不清的域已显式顺延 +[ ] P3 架构:api/auth/worker/mq 四服务;会话三道校验 + 单飞重登;凭据外置;默认无DB(见 §4.1) +[ ] P3 架构:若引入 PG → 连接预算表 + pgbouncer(多副本必走)+ 小池(pool≤5) +[ ] P3 文档:design.md(里程碑 + 风险清单) +[ ] P4 代码:通用 _request + 按域 fetch/normalize + OPS 分发 + 瘦路由;归一化先透传后精修 +[ ] P5 部署:遵守目标环境规范;脚本处理权限/端口/容器ID/同tag强制刷新 +[ ] P6 冒烟:逐端点真实验证 + meta;样本落盘 docs/samples +[ ] P7 文档:api.md(真实示例 + 开放边界);凭据脱敏;误提交则改写历史并轮换 +``` + +--- + +## 10. 一页纸心法 + +- **浏览器探路,HTTP 搬货。** +- **先契约,后代码。** +- **会话集中、取数无状态、派发异步。** +- **按域闭环,架构不动。** +- **样本即文档,文档即事实。** +- **凭据永不入库,泄露即轮换。** +- **轻量抓取默认无 PG;要落库先算连接数,多副本必走 pgbouncer。**