5.2 KiB
淘宝/天猫选择器实测记录
实测日期: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. 复测脚本
改版后重跑,对照本文档的证据列:
(() => {
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));
})();