Files
ozon-seller-kit/docs/extension/selectors-taobao.md
T
2026-08-11 17:09:23 +08:00

127 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 淘宝/天猫选择器实测记录
> 实测日期:2026-08-11
> 页面:`detail.tmall.com/item.htm?id=960057430812`、`item.taobao.com/item.htm?id=1060253247160`
> 方法:反向扫描(dump 页面实际类名前缀,而非猜名字去查)
> 对应实现:`extension/src/profiles/taobao.ts`
---
## 1. 结论
**两站 DOM 完全一致**,同一套前端(`PageFramework--` / `tbpc-layout` / `keyInfo--` 骨架相同),一份 profile 覆盖淘宝与天猫。
类名形如 `mainTitle--HASH`,是 CSS Modules 产物:**语义前缀稳定,哈希后缀每次构建变**。因此选择器一律写 `[class*="前缀--"]`
结尾的 `--` 不能省——它把父容器和子元素区分开:`generalParamsInfoItem--` 不会误命中 `generalParamsInfoItemTitle--`
---
## 2. 确证的选择器
| 目标 | 选择器 | 实测证据 |
|---|---|---|
| 标题 | `[class*="mainTitle--"]` | n=2 imgs=0,纯文本节点。天猫「迷你特工队玩具X弗特…」淘宝「对插双刀流发光双刃剑…」 |
| 标题兜底 | `[class*="MainTitle--"]` `[class*="ItemTitle--"]` | 外层容器,天猫版带图标(imgs=2) |
| 价格 | `[class*="highlightPrice--"]` | 淘宝 `¥5.2`,天猫 `秒杀价¥27.72` |
| 价格兜底 | `[class*="priceWrap--"]` | 会带上「优惠前¥36.8」,故仅兜底 |
| 主图 | `[class*="picGallery--"] img` / `#picGalleryEle` | 天猫 imgs=6,淘宝 imgs=7 |
| 主图缩略 | `[class*="thumbnailPic--"]` | n=5/6 |
| SKU 容器 | `[class*="valueItem--"]` | **n=22 imgs=22**(天猫),每项恰含一张 img |
| SKU 规格名 | `[class*="valueItemText--"]` | 「特工x武器小【弗特】2种形态- 可变形」 |
| 参数项 | `[class*="generalParamsInfoItem--"]` | Title=「品牌」SubTitle=「劣狐狐(模玩)」 |
| 详情区 | `[class*="tabDetailWrap--"]` `[class*="detailInfo--"]` | 淘宝 imgs=7 |
---
## 3. 两个反直觉的点
### 3.1 淘宝 SKU 是真实 `<img>`,不是 CSS 背景图
**与 1688 相反。** 探测数据:
```
valueItem n=22 imgs=22 ← 容器,每项含 1 张 img
valueItemImgWrap n=22 imgs=22 ← 图片包裹层
valueItemImg n=22 imgs=0 ← img 元素本身(querySelectorAll('img') 查自己得 0
valueItemText n=22 imgs=0 ← 规格名文本
```
`imgs=0` 恰恰证明 `valueItemImg--` 就是 `<img>`。所以淘宝 profile **不能**用 `srcProps: ['backgroundImage']`1688 必须用)。
引擎为此补了一段兜底:选择器命中容器且未取到 URL 时,往下找一层 `querySelector('img')`(见 `collector/image.ts`)。
### 3.2 主图组不设 minWidth
`picGallery--` 里同时有大图和缩略图,缩略图 `naturalWidth` 只有 60 左右。按 `minWidth: 200` 过滤会把主图**全部误杀**。
不过滤是安全的,因为 `toOriginalUrl()` 会把两种尺寸都还原成同一个原图 URL,`dedupeKey` 相同即自动去重。
---
## 4. 两个失效的既有假设
### 4.1 页面上没有 `<h1>`
`document.querySelector('h1')` 返回 null。旧 profile 里的 `.tb-detail-hd h1``h1[data-spm]`、裸 `h1` 全部无效,`readySelectors` 也不能用 `h1` 探活。
### 4.2 没有 JSON-LD
两站 `script[type="application/ld+json"]` 都是**空数组**。
`plan-revision.md` R3 里"JSON-LD 比 DOM 选择器稳定一个数量级"的推测**对淘宝不成立**(对 Ozon 仍待验证)。淘宝只能走 DOM。
---
## 5. 待办
### 5.1 desc 暂不采集
`detailInfo--` 容器里混着用户评价、参数信息、图文详情三块,`extract: 'join'` 出来是无法使用的一坨。考虑到 1688/淘宝的中文文案对 Ozon 价值本就低(需重写),一期跳过。
若以后要采,需先定位「图文详情」那个 `tabDetailItem--` 的稳定标识。
### 5.2 详情图需要用户操作
图文详情是懒加载 + tab 切换。用户不点开「图文详情」tab 就采不到。`scan.ts` 已有 `stats.detail === 0` 的警告。
### 5.3 内嵌数据待评估
`window` 上有一批可能有用的键,但**当前架构读不到**——MV3 content script 默认跑在 isolated world,看不见页面 `window`。要读需 `world: 'MAIN'` 或注入 script 标签。
值得关注的:
```
__general_skupanel_cache_data ← 可能含完整 SKU 结构
__ICE_DATA_LOADER__ ← ICE 框架的数据层
__itempage_openapi
g_config
```
如果 `__general_skupanel_cache_data` 真含 SKU 数据,比 DOM 抓 22 个 `valueItem--` 可靠得多。二期评估。
---
## 6. 复测脚本
改版后重跑,对照本文档的证据列:
```js
(() => {
const KEY = /(title|name|main|pic|img|gallery|thumb|sku|value|desc|detail|param|price)/i;
const pfx = new Map();
document.querySelectorAll('*').forEach(el => {
if (typeof el.className !== 'string') return;
el.className.split(/\s+/).forEach(c => {
const m = c.match(/^([A-Za-z][A-Za-z0-9]*)--/);
if (!m || !KEY.test(m[1])) return;
const r = pfx.get(m[1]) ?? { prefix: m[1], n: 0, imgs: 0, sample: '' };
r.n++; r.imgs += el.querySelectorAll('img').length;
if (!r.sample) r.sample = (el.textContent || '').trim().slice(0, 40);
pfx.set(m[1], r);
});
});
console.table([...pfx.values()].sort((a, b) => b.n - a.n).slice(0, 40));
})();
```