110 lines
7.4 KiB
Markdown
110 lines
7.4 KiB
Markdown
# V2.1 采集方案(以 image-suite-studio 为主要参考)
|
||
|
||
> 状态:方案定稿(Phase C 实施)
|
||
> 参考项目:`/Users/joey-xd/sites/seller-store/image-suite-studio`(下称 ISS)
|
||
> 原则:**采集功能以 ISS 的实现为准**。ISS 的采集引擎本就与本仓 extension-v1/v2 同源,V2.1 把 ISS 的最新版采集实现(含 1688/淘宝与页内悬浮面板)合并回本仓,并接上本仓已有的服务端上传链路。
|
||
|
||
---
|
||
|
||
## 1. 采集形态与架构(照搬 ISS)
|
||
|
||
Chrome MV3 扩展(WXT + React + antd),四个 content script 注入三个平台的四个站点:
|
||
|
||
| 站点 | 匹配 |
|
||
|---|---|
|
||
| Ozon | `*.ozon.ru` / `*.ozon.kz` / `*.ozon.by` |
|
||
| 1688 | `detail.1688.com` |
|
||
| 淘宝/天猫 | `item.taobao.com` / `detail.tmall.com` |
|
||
|
||
```
|
||
extension/
|
||
├── entrypoints/
|
||
│ ├── background.ts # Service Worker,唯一出网口(上传/代理 fetch)
|
||
│ ├── content/index.ts # 采集脚本(isolated world),挂 window.__SuiteCollector
|
||
│ ├── bridge.content.ts # MAIN world 桥:postMessage 读页面全局变量(window.context / __ICE_APP_CONTEXT__)
|
||
│ └── panel.content.ts # 页内悬浮按钮「套」+ 右侧滑出面板(Shadow DOM + iframe 懒加载)
|
||
├── src/
|
||
│ ├── collector/ # 采集引擎(见 §2)
|
||
│ ├── profiles/ # 声明式站点配置(ozon/1688/taobao)
|
||
│ ├── api/client.ts # 上传 payload 组装
|
||
│ └── storage/settings.ts# baseUrl/token/水印设置
|
||
└── entrypoints/sidepanel/ # 面板 UI(App.tsx,iframe 复用)
|
||
```
|
||
|
||
UI 交互形态采用 ISS 的**页内悬浮面板**(在商品页右侧滑出,iframe 加载 sidepanel.html),
|
||
比 Chrome 原生 Side Panel 更贴近「边看商品边采集」的操作。
|
||
|
||
## 2. 采集引擎(多源合并,主路径优先、DOM 兜底)
|
||
|
||
统一入口 `src/collector/scan.ts`:`scanCurrentPage()` → `matchProfile(location.href)` → 分发平台文件 → `merge.ts` 装配 `ScanResult`。
|
||
|
||
| 平台 | 主路径 | 兜底/补充 | 关键实现(ISS 路径) |
|
||
|---|---|---|---|
|
||
| **Ozon** | ① SSR `data-state` widget 白名单(webGallery/webPrice/webProductHeading/webShort\|Detailed\|Characteristics/webAspects/webReviewProductScore/breadCrumbs) | ② JSON-LD ③ 站内 `entrypoint-api.bx` JSON(两 URL 合并:默认页 + `?layout_page_index=2` 描述页)④ DOM 选择器 + 模拟人工滚动触发懒加载 | `collector/ozon-state.ts`、`jsonld.ts`、`ozon-api.ts`、`platforms/ozon.ts` |
|
||
| **淘宝/天猫** | ① MAIN world 桥读 `__ICE_APP_CONTEXT__`(loaderData…item/skuBase/priceVO/参数表;SKU 缺失从 `__general_skupanel_cache_data` 容错深搜;**不调 mtop 签名接口防风控**) | ② DOM(CSS Modules 前缀匹配 `[class*="mainTitle--"]`;详情图 `excludeWithin` 排除评价/推荐;**desc 故意不采**) | `collector/taobao-state.ts`、`ssr.ts`、`platforms/taobao.ts` |
|
||
| **1688** | ① MAIN world 桥读 `window.context`(deepFind BFS:gallery/tempModel/skuModel.skuProps 全维展开 + skuMapOriginal 价格库存 + pieceWeightScaleInfo 自动生成尺寸重量参数/productAttributes) | ② DOM(`#productAttributes` cells 模式参数表、`#detail` 详情图) | `collector/1688-state.ts`、`platforms/1688.ts` |
|
||
|
||
通用提取器(照搬):`text.ts`(join/first/table/cells 四模式)、`image.ts`(srcProps 降级链 + srcset 挑最大 + Shadow DOM 穿透 + SKU 按 `url::规格名` 去重)、`url.ts`(原图还原:Ozon `/wc\d+/`、阿里 `xxx.jpg_400x400.jpg → xxx.jpg`;`toThumbUrl` 反向缩略图)、`merge.ts`(primary 先入 fallback 填缺,按 dedupeKey 去重,重排 main→sku→detail→video)。
|
||
|
||
### 采集数据结构(ScanResult,与 ISS 完全一致)
|
||
|
||
```jsonc
|
||
{
|
||
"platform": "ozon | 1688 | taobao",
|
||
"itemId": "…|null", "url": "…", "scannedAt": 1724000000000,
|
||
"source": "state | ssr | jsonld | api | dom | mixed",
|
||
"breadcrumbs": [ { "name": "…", "href": "…", "searchCategoryId": 7041 } ], // 仅 Ozon
|
||
"stats": { "main": 8, "sku": 6, "detail": 12, "video": 1 },
|
||
"warnings": ["详情图为 0 张,请滚动到页面底部后重新采集"],
|
||
"texts": [ { "kind": "title|price|params|selling_point|desc|brand|sales|shop",
|
||
"content": "…", "pairs": [ { "key": "材质", "value": "PP塑料" } ] } ],
|
||
"images": [ { "key": "main-001", "groupKey": "main", "groupName": "主图",
|
||
"variantName": "粉色", "url": "原图URL", "thumbUrl": "缩略图URL",
|
||
"index": 0, "type": "img|video", "width": 800, "height": 800 } ]
|
||
}
|
||
```
|
||
|
||
## 3. 采集后双动作(V2.1 新增)
|
||
|
||
ISS 采集完是「本地展示 + 生图」,本仓在其后追加落库与跳转:
|
||
|
||
```
|
||
快速采集(悬浮面板)
|
||
│ scanCurrentPage() → ScanResult
|
||
▼
|
||
① 同步到采集箱:POST /api/materials(本仓已实现)
|
||
│ payload = { platform, item_id, url, texts, images: [{url, group_key, variant_name, dedupe_key, width, height, type}] }
|
||
│ 响应 { product_id, created } ← 服务端已有返回,插件此前未用,Phase C 起使用
|
||
▼
|
||
② 自动打开商品试算页:chrome.tabs.create({ url: `${studioBaseUrl}/trial/${product_id}` })
|
||
│ studioBaseUrl 存插件设置(默认 http://localhost:8900)
|
||
▼
|
||
面板内提示「已入库并打开试算页」,用户可直接在试算页继续流水线
|
||
```
|
||
|
||
要点:
|
||
- `POST /api/materials` 的 texts/images 契约已对齐 ScanResult(extension-v2 现有 `buildMaterialsPayload` 可直接复用)。
|
||
- 重复采集同一商品:服务端按 `platform + item_id` 复用 Product(已实现),插件拿到同一 `product_id`,打开试算页即回到原商品。
|
||
- 1688/淘宝素材上传:`_apply_texts` 平台无关,参数表/重量/尺寸解析已兼容(`_apply_weight_dims` 的 kg→g、cm→mm 换算同样适用 1688 的 `pieceWeightScaleInfo`)。
|
||
|
||
## 4. extension-v2 改造清单(Phase C)
|
||
|
||
| # | 改动 | 说明 |
|
||
|---|---|---|
|
||
| 1 | 用 ISS 的 `src/collector`、`src/profiles`、`src/bridge` 整体替换 extension-v2 对应目录 | ISS 版本更新(含 1688/淘宝 + 多项修复),以 ISS 为准 |
|
||
| 2 | 新增 `panel.content.ts` 页内悬浮面板入口 | 保留原生 Side Panel 入口,两种方式共存 |
|
||
| 3 | 面板 UI(sidepanel/App.tsx)以 ISS 版为基线,去掉「出图方案/生成结果」区块 | 生图移到试算页做(屏幕更大、可对照商品信息);面板保留:采集结果核对/编辑、勾选图片、上传、下载采集图 |
|
||
| 4 | 上传成功后读响应 `product_id`,`chrome.tabs.create` 打开 `{studio}/trial/{product_id}` | 设置项 `studioBaseUrl` |
|
||
| 5 | background 保持唯一出网口(代理图片 fetch 绕防盗链 + 上传) | 已是现状 |
|
||
| 6 | `GET /api/collected?platform=&itemId=` 采集前查重提示 | 已有接口,面板显示「已采集过,将打开原商品」 |
|
||
|
||
## 5. 与 ISS 的差异总表
|
||
|
||
| 维度 | ISS | 本仓 V2.1 |
|
||
|---|---|---|
|
||
| 采集引擎 | 三平台完整版 | **相同**(Phase C 平移) |
|
||
| 采集结果去向 | 仅面板展示(无持久化) | 落库 products/product_assets(复用 V2 已实现) |
|
||
| 生图入口 | 面板内 03/04 区块 | 移到 studio 试算页(功能对齐 + 单张 AI 生图增强) |
|
||
| 生图后端 | 独立 server(3300 端口,无鉴权) | 并入本仓 server(8800,JWT;Phase B 平移) |
|
||
| 采集后动作 | 无 | 入库 + 自动打开 `/trial/{id}` |
|