with one click
dxm-attributes
店小秘速卖通编辑页——属性信息模块:产品属性批量填(ant-select CDP填充)+ 自定义属性删除
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
店小秘速卖通编辑页——属性信息模块:产品属性批量填(ant-select CDP填充)+ 自定义属性删除
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
速卖通店铺运营自动化 — 每日巡检/每周策略/商品上架/数据分析全流程。填入你的店铺名即可使用。
店小秘速卖通编辑页——基本信息模块:标题改英文 + 产品分类选择
速卖通上架——1688采集模块:从1688搜索产品 → 采集到店小秘采集箱 → 提取产品参数(价格/库存/重量/材质等)
店小秘速卖通编辑页——店小秘信息模块:来源URL(只读,记录用)
店小秘速卖通上品完整工作流——从采集箱到发布的所有模块编排、调用顺序、区域调价、保存发布
店小秘速卖通编辑页——其他信息模块:半托管/关税/责任人/制造商/资质 + 区域调价 + 保存并移入待发布
| name | dxm-attributes |
| description | 店小秘速卖通编辑页——属性信息模块:产品属性批量填(ant-select CDP填充)+ 自定义属性删除 |
| domain | ecommerce |
| triggers | ["用户说\"填属性\"、\"产品属性\"、\"属性信息\"、\"删自定义属性\"","店小秘编辑页打开后需要填属性信息"] |
CDP browser_cdp 直连。编辑页 target_id 通过 Target.getTargets 获取。
Runtime.evaluate:
const links = document.querySelectorAll('.anchor-menu-item, a');
for (const l of links) {
if (l.textContent.trim() === '属性信息') { l.click(); break; }
}
在填属性之前,需要从1688获取产品参数。
Runtime.evaluate (在编辑页 target):
const links = document.querySelectorAll('a');
for (const l of links) {
if (l.href && l.href.includes('detail.1688.com')) return l.href;
}
Target.createTarget: { url: 1688_URL }
详见 references/1688-json-extraction.md:
window.__INIT_DATA__ 或 <script> 内 JSON2026-07-18/19 血训(两次!):
类名是 span.attr-label.required,不是 .ant-form-item-required!
// 正确检测星号
labelEl.querySelector('span.attr-label.required')
// 完整枚举所有星号字段及当前值
Array.from(document.querySelectorAll('#attrInfo .ant-form-item'))
.filter(item => item.querySelector('span.attr-label.required'))
.map(item => ({
label: item.querySelector('label').innerText.trim(),
value: item.querySelector('.ant-select-selection-item')?.textContent?.trim() || '(empty)'
}));
| 属性 | 来源 | 常用值 |
|---|---|---|
| 产地 | 固定 | 中国大陆 |
| 省份 | 固定 | 浙江(义乌产) |
| 品牌 | 固定 | NONE |
| 材质 | 1688 | 硅胶→塑料(无硅胶选项时), 不锈钢, 尼龙等 |
| 高关注化学品 | 固定 | 天然未处理 |
| 类型 | 1688 | 狗狗/猫咪/通用 |
| 液晶显示 | 推断 | 无(No) — 宠物水杯无LCD |
| 最大出餐量 | 推断 | 选中间值(如水杯500g) |
| 最小出餐量 | 推断 | 选最小值(如水杯100g) |
| 是否智能 | 推断 | no(no) — 宠物水杯非智能 |
| 是否包含电池 | 推断 | no(no) — 宠物水杯无电池 |
| 电源 | 推断 | 无数据跳过 |
| 电压 | 1688 | 无数据跳过(共享下拉池重灾区) |
| 动力来源 | 推断 | 无数据跳过 |
| 承受重量 | 1688 | 无数据跳过 |
| 季节/特性 | 1688 | 无数据跳过(这些可能是空下拉) |
首选方案(下拉已初始化时):JS强制显示 + 点击(2026-07-19 验证)
⚠️ 此方案仅当dropdown已有option时有效。 全新编辑页需先Playwright mouse.click打开每个下拉初始化option。
Playwright mouse.click 坐标法在此页面上不可靠(坐标偏移、dropdown不出现、CDP relay频繁断连)。
真正有效的方案是纯JS操作——找到含目标选项的dropdown → 强制显示 → 点击选项。Vue 3会自动拾取点击事件并更新组件状态。
// 批量填充(通过 browser_cdp Runtime.evaluate 执行)
(function(){
var targets = ['中国大陆(Origin)(Mainland China)', 'NONE(NONE)', '无(No)',
'500g(500g)', '100g(100g)', '塑料(Plastic)',
'no(no)', '天然未处理(None)', 'no(no)'];
for (var t = 0; t < targets.length; t++) {
var target = targets[t];
var dds = document.querySelectorAll('.ant-select-dropdown');
for (var i = 0; i < dds.length; i++) {
var dd = dds[i];
var items = dd.querySelectorAll('.ant-select-item-option');
for (var j = 0; j < items.length; j++) {
if (items[j].textContent.trim() === target) {
dd.classList.remove('ant-select-dropdown-hidden');
dd.style.display = '';
dd.style.opacity = '1';
dd.style.pointerEvents = 'auto';
items[j].scrollIntoView({block: 'nearest'});
items[j].click();
items[j].dispatchEvent(new MouseEvent('mousedown', {bubbles: true}));
items[j].dispatchEvent(new MouseEvent('mouseup', {bubbles: true}));
break;
}
}
}
}
})()
⚠️ 批量填充陷阱: 当多个dropdown同时被显示时,no(no) 这类重复选项会匹配到错误的dropdown。对于重复选项值,必须逐个字段填充,每次填充后关闭所有dropdown再填下一个。
⚠️ Dropdown损坏陷阱(2026-07-19 发现): 对 dropdown 频繁执行 dd.style.display='none' + dd.classList.add('ant-select-dropdown-hidden') 会导致所有 dropdown 的 option 数量变为 0(querySelectorAll('.ant-select-item-option').length === 0)。只能重新加载页面才能恢复。 发现 0 items 时不要继续尝试——刷新页面重来。
⚠️ 批量填充后验证: JS批量填充后必须逐字段验证。不要因为8/9就声称"完成"。用户对"验证通过"的定义是所有带星号字段全部填完。
降级方案:Playwright坐标法(CDP relay正常时可用)
1. 【点】获取 selector DOM 坐标,打开下拉
Input.dispatchMouseEvent(type='mousePressed', x, y)
Input.dispatchMouseEvent(type='mouseReleased', x, y)
2. 【选】匹配选项并点击
Runtime.evaluate:
const drops = document.querySelectorAll('.ant-select-dropdown:not(.ant-select-dropdown-hidden)');
for (const d of drops) {
d.querySelectorAll('.ant-select-item-option').forEach(item => {
if (item.textContent.includes('目标值')) { item.click(); }
});
}
3. 【JS隐藏】强制关闭所有dropdown(Escape在CDP下无效!)
Runtime.evaluate:
document.querySelectorAll('.ant-select-dropdown').forEach(d => {
d.classList.add('ant-select-dropdown-hidden');
});
4. 【移动】到下一个 select,重复步骤 1
ant-design 的 select dropdown 打开后仍在 DOM 中且有一个透明遮罩。如果不关闭,下一个 select 的 click 会打在遮罩上,完全无效。
❗ CDP 下的关键发现:Input.dispatchKeyEvent Escape 无法关闭 ant-select dropdown。 必须用 JS classList.add('ant-select-dropdown-hidden') 强制隐藏。
店小秘的电压和功率字段共享同一个下拉数据池。如果连续 3 次选不上——停手,开新标签页先填这两个字段,不要死磕。
自定义属性的 DOM 结构不是 .ant-tag,而是 div.custom-attr-item。每行含两个 <input>(属性名/属性值)和一个关闭按钮。
查询(browser_cdp Runtime.evaluate):
(function(){
var items = document.querySelectorAll('#attrInfo .custom-attr-item');
var vals = [];
items.forEach(function(a){
var inputs = a.querySelectorAll('input');
if (inputs.length >= 2) vals.push(inputs[0].value + '=' + inputs[1].value);
});
return JSON.stringify(vals);
})()
「批量操作→删除全部→确 定」路径未经实测验证。实际验证有效的方案是直接逐条点击关闭图标:
# Playwright(需 CDP relay 正常)
# 1. 滚动到自定义属性区域
await page.evaluate("document.querySelector('#attrInfo .smtCustomAttrs').scrollIntoView({block: 'center'})")
# 2. 获取自定义属性总数
count = await page.evaluate("document.querySelectorAll('#attrInfo .custom-attr-item').length")
# 3. 逐个点击关闭图标(.icon_close 类名,不是 .anticon-close!)
for i in range(count):
close_btn = page.locator("#attrInfo .custom-attr-item .icon_close").first
await close_btn.click(force=True, timeout=3000)
await asyncio.sleep(0.3)
# 4. 验证
remaining = await page.evaluate("document.querySelectorAll('#attrInfo .custom-attr-item').length")
⚠️ 关闭按钮类名是 iconfont icon_close,不是 .anticon-close 或 .ant-tag-close-icon! JS element.click() 无效——Vue 组件需要 Playwright 真点击。
❌ 已证伪的方法:
element.click() / dispatchEvent('click') → Vue 不认,删不掉Input.dispatchMouseEvent → 坐标难定位classList.add('ant-select-dropdown-hidden') 关闭,CDP Escape 无效!innerText.trim() 而非 textContent.trim()item.querySelector('.ant-select-selector').getBoundingClientRect(),不要用 label 坐标window.context JSON(productPackInfo.fields.pieceWeightScale)+ 页面文本双路径connect_over_cdp('http://127.0.0.1:19223') 偶发超时(3分钟超时),症状为所有后续 Playwright 操作全部失败。此时必须检修 relay 链路:kill relay进程 → taskkill chrome → 重启Chrome(带--remote-debugging-port=9222) → 重启Relay2.exe → 重启WSL relay → 更新browser.cdp_url。参考 aliexpress-store-ops/references/chrome-cdp-relay.md 检修脚本。selector.click() + dispatchEvent(MouseEvent) 能打开dropdown,但 querySelectorAll('.ant-select-dropdown') 可能返回错误字段的dropdown。表现:点品牌→dropdown显示产地选项,点最大出餐→dropdown显示液晶选项。唯一有效缓解: ①每次操作前 classList.add('ant-select-dropdown-hidden') 强制关闭所有dropdown ②用 dds[dds.length-1] 取最新打开的dropdown ③每字段等待1.5s以上让Vue渲染完毕。但即使遵守以上规则,成功率仍非100%。如连续3个字段失败,放弃属性模块,先填其他模块,最后通知用户手动修正。 属性字段是店小秘自动化中最脆弱的一环。dd.classList.remove('ant-select-dropdown-hidden') 强制显示后 querySelectorAll('.ant-select-item-option') 返回空数组。必须先Playwright page.mouse.click(selector坐标) 打开下拉 → option渲染到DOM → 再用JS或keyboard选值。 此问题仅在首次填写时出现,之前填过的字段仍有option残留。✅ 唯一有效方法:Playwright keyboard.type() + 点击空白处 blur(不要按 Enter!)
1. page.mouse.click(selector坐标) → 打开并聚焦
2. page.keyboard.press("Control+a") → 全选
3. page.keyboard.press("Backspace") → 清空
4. page.keyboard.type("300g", delay=40~80) → 逐字符键入
5. await asyncio.sleep(1.5) → 等 auto-complete 匹配
6. page.mouse.click(500, 100) → 点页面空白处 blur 提交(⚠️ 不能按 Enter!)
🚨 关键坑:不能按 Enter! Enter 会清空 auto-complete 的值。正确做法是点击页面其他地方让 input 失去焦点(blur),Vue 会在 blur 时提交值。
验证 auto-complete: 值存储在 input.value 中,不在 .ant-select-selection-item 中。验证代码必须分别处理:
const item = sel.querySelector('.ant-select-selection-item');
const inp = sel.querySelector('input');
const val = (item && item.textContent.trim()) || (inp && inp.value) || '';
const filled = val !== '' && !sel.querySelector('.ant-select-selection-placeholder')?.offsetParent;
❌ 已证伪的方法:
nativeInputValueSetter + dispatchEvent('input') → 值不持久化keyboard.type() + keyboard.press("Enter") → 值被清空keyboard.press("Tab") → 提交裸字符串,不带括号部分(如 "300" 而非 "300g(300g)")document.execCommand('insertText') → 值被组件截断⚠️ 中文输入: page.keyboard.press("塑") 会报错 Unknown key。中文必须用 page.keyboard.type("塑料")。
已知 auto-complete 字段示例:最大出餐量、材质。
作者: Rigi AI Commons | 小红书 @瑞吉AI人民公社 | AI自动化专家工作流