店小秘多平台铺货配方:7 平台建品脚本 + 静默拦截诊断法 + 项目状态
- TikTok/Shopee/速卖通/Walmart 各 46-47 条已在待发布 - Ozon 47 条已建、改价 40/47 - SHEIN 配方跑通第一条;Temu 差「预览图」一步 - 核心产出:MYJ.message.error 钩子诊断法(解开了三个平台的保存静默拦截) - 含下一轮提示词 NEXT-ROUND-PROMPT.md
This commit is contained in:
commit
f5720ad613
94 files changed
+21561
No files matched your search
@@ -0,0 +1,25 @@
|
||||
# SHEIN 建品配方(已跑通第一条)
|
||||
|
||||
## 完整流程
|
||||
1. `https://www.dianxiaomi.com/web/sheinProduct/add`
|
||||
2. **选店铺**(按品类分店,见 shein_route.json)
|
||||
3. **选类目**:点「选择分类」→ 弹窗 `input[placeholder="搜索分类名称"]` → 搜索 → 点 `.search-result-item`
|
||||
4. **标题**:`sheinAddProductStore.formState.productName`
|
||||
5. **★ 加第二个规格**:点 `.theme-select-box` 里的 `尺寸(Size)`
|
||||
—— 这是之前一直卡住的关键!类目要求**颜色+尺寸两个规格**,只选颜色不行
|
||||
6. **选规格值**:两个 `.sku-info-box` 里各点一个 `.sku-option`(要点里面的 `label.d-checkbox`)
|
||||
7. **填 SKU 行**:`sheinSkuDataStore.formState.skuDataList[]`
|
||||
`skcSupplierCode / skcRetailPrice / supplyPrice / stockVariety / weight / length / width / height`
|
||||
⚠️ **加第二个规格会重建 SKU 行,之前的填充会丢** —— 必须在规格选完之后再填
|
||||
8. **尺码表**:点「编辑尺码表」→ 弹窗内 6 个 `placeholder="请输入"` 的 input → 点「确定」
|
||||
9. **图片**:`sheinImgStore.formState.mainImgData.multipleSpuImgs` → **数组**
|
||||
10. **保存** → `POST /api/sheinProduct/add.json`
|
||||
|
||||
## 关键教训
|
||||
- 报错 `有必选规格未选择` 的真实含义是:**类目定义的规格没选全**,不是主规格没值
|
||||
- 加规格会重置 SKU 行 → **顺序不能错**:先规格、后 SKU、再尺码表
|
||||
- 所有报错都会被 `MYJ.message.error` 吞掉,必须挂钩子才看得到
|
||||
|
||||
## 待批量
|
||||
- 40 条按品类分到 4 家店(美妆18 / 文具13 / 箱包8 / 内睡袜子1)
|
||||
- 需要把上述流程写成 `shbatch.mjs`,逐条跑
|
||||
@@ -0,0 +1,22 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
const r = await c.evalJS(`(()=>{const box=[...document.querySelectorAll('.theme-select-box')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!box)return'nf';
|
||||
const chips=[...box.querySelectorAll('*')].filter(e=>e.offsetParent!==null&&/^\\s*尺寸\\(Size\\)\\s*$/.test((e.innerText||'').trim()));
|
||||
if(!chips.length)return'no-chip';
|
||||
const el=chips[chips.length-1];
|
||||
for(const ev of ['mousedown','mouseup','click']) el.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window}));
|
||||
return 'clicked';})()`);
|
||||
console.log('点尺寸:', String(r));
|
||||
await wait(4000);
|
||||
const o = await c.evalJS(`(()=>{const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const a=JSON.parse(JSON.stringify(p._s.get('sheinSkuAttrStore').$state));
|
||||
const boxes=[...document.querySelectorAll('.sku-info-box')].filter(e=>e.offsetParent!==null).map((b,i)=>({
|
||||
i, txt:(b.innerText||'').replace(/\\s+/g,' ').slice(0,90), opts:b.querySelectorAll('.sku-option').length,
|
||||
sels:[...b.querySelectorAll('.ant-select')].map(s=>(s.innerText||'').replace(/\\s+/g,' ').slice(0,16)),
|
||||
ins:[...b.querySelectorAll('input')].filter(i=>i.offsetParent!==null&&i.type!=='checkbox').map(i=>({ph:i.placeholder||'',cls:String(i.className||'').slice(0,40)})).slice(0,4)}));
|
||||
const btns=[...document.querySelectorAll('button')].filter(b=>b.offsetParent!==null&&/添加/.test(b.innerText||'')).map(b=>({t:(b.innerText||'').trim(),dis:b.disabled}));
|
||||
return JSON.stringify({attrs:(a.formState.skuAttrs||[]).map(x=>({n:x.name, opts:(x.options||[]).length})), boxes, btns},null,1);})()`);
|
||||
console.log(String(o).slice(0,1400));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,21 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
const reqs=[];
|
||||
c.on(m=>{ if(m.method==='Network.requestWillBeSent'){const r=m.params.request;
|
||||
if(/shein/i.test(r.url)&&/\.json/.test(r.url)&&r.method==='POST') reqs.push(r.url.replace('https://www.dianxiaomi.com','')); }});
|
||||
await c.send('Network.enable').catch(()=>{});
|
||||
const btns = await c.evalJS(`(()=>[...document.querySelectorAll('button')].filter(e=>e.offsetParent!==null).map((b,i)=>{
|
||||
const r=b.getBoundingClientRect(); return {i, t:(b.innerText||'').replace(/\\s+/g,' ').trim().slice(0,14), y:Math.round(r.y), dis:b.disabled};}).filter(x=>x.t))()`);
|
||||
console.log('按钮:', JSON.stringify(btns).slice(0,700));
|
||||
// 点“保存”并立刻轮询任何反馈
|
||||
await c.evalJS(`(()=>{const x=[...document.querySelectorAll('button')].filter(e=>e.offsetParent!==null).find(e=>/^\\s*保存\\s*$/.test((e.innerText||'').trim()));
|
||||
if(x){ for(const ev of ['mousedown','mouseup','click']) x.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); } return 1;})()`);
|
||||
const seen=[];
|
||||
for(let i=0;i<18;i++){ await wait(700);
|
||||
const m=await c.evalJS(`(()=>{const a=[...document.querySelectorAll('.ant-message-notice,.ant-notification-notice,.ant-modal-confirm,.ant-modal')].filter(e=>e.offsetParent!==null)
|
||||
.map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim().slice(0,130)).filter(Boolean); return JSON.stringify(a.slice(0,3));})()`);
|
||||
JSON.parse(String(m)).forEach(x=>seen.push(x)); }
|
||||
console.log('反馈:', [...new Set(seen)].slice(0,4).join(' || ').slice(0,400));
|
||||
console.log('POST:', JSON.stringify([...new Set(reqs)].slice(0,4)));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,22 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
const o = await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/产品分类/.test(l.innerText||'');});
|
||||
if(!it)return'nf'; return JSON.stringify({txt:(it.innerText||'').replace(/\\s+/g,' ').slice(0,120), html:it.innerHTML.slice(0,600)});})()`);
|
||||
console.log('分类控件:', String(o).slice(0,900));
|
||||
const pos = JSON.parse(String(await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/产品分类/.test(l.innerText||'');});
|
||||
if(!it)return'[]'; const el=it.querySelector('.ant-select-selector')||it.querySelector('input');
|
||||
if(!el)return'[]'; el.scrollIntoView({block:'center'}); const r=el.getBoundingClientRect();
|
||||
return JSON.stringify([Math.round(r.x+r.width/2),Math.round(r.y+r.height/2)]);})()`)));
|
||||
if(pos.length){ for(const type of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type,x:pos[0],y:pos[1],button:'left',clickCount:1}); await wait(4000); }
|
||||
const o2 = await c.evalJS(`(()=>{
|
||||
const ms=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null).map(m=>({t:(m.querySelector('.ant-modal-title')||{}).innerText||'',
|
||||
inputs:[...m.querySelectorAll('input')].map(i=>i.placeholder||i.type).slice(0,5),
|
||||
btns:[...m.querySelectorAll('button')].map(b=>(b.innerText||'').trim()).slice(0,6),
|
||||
txt:(m.innerText||'').replace(/\\s+/g,' ').slice(0,300)}));
|
||||
const dd=[...document.querySelectorAll('.ant-select-dropdown')].filter(e=>e.offsetParent!==null).map(d=>(d.innerText||'').replace(/\\s+/g,' ').slice(0,260));
|
||||
return JSON.stringify({modals:ms, dropdowns:dd},null,1);})()`);
|
||||
console.log(String(o2).slice(0,1400));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,26 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
const pick = await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/主规格/.test(l.innerText||'');});
|
||||
if(!it)return'nf'; const box=it.querySelector('.sku-info-box')||it;
|
||||
const opts=[...box.querySelectorAll('.sku-option')].filter(e=>e.offsetParent!==null);
|
||||
const hit=opts.find(e=>/Black\\(/.test(e.innerText||''))||opts[0];
|
||||
if(!hit)return'no-opt';
|
||||
const lab=hit.querySelector('label'); const inp=hit.querySelector('input[type=checkbox]');
|
||||
if(lab) for(const ev of ['mousedown','mouseup','click']) lab.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window}));
|
||||
if(inp && !inp.checked) inp.click();
|
||||
return 'clicked:'+(hit.innerText||'').trim()+' checked='+(inp?inp.checked:'?');})()`);
|
||||
console.log('点色:', pick);
|
||||
await wait(7000);
|
||||
const o = await c.evalJS(`(()=>{
|
||||
const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const tbls=[...document.querySelectorAll('table')].filter(t=>t.offsetParent!==null).map(t=>({
|
||||
th:[...t.querySelectorAll('th')].map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim()).slice(0,15),
|
||||
rows:[...t.querySelectorAll('tbody tr')].filter(x=>x.querySelectorAll('input').length).length}));
|
||||
const d=JSON.parse(JSON.stringify(p._s.get('sheinSkuDataStore').$state));
|
||||
const a=JSON.parse(JSON.stringify(p._s.get('sheinSkuAttrStore').$state));
|
||||
return JSON.stringify({tbls, n:(d.formState.skuDataList||[]).length, row0:(d.formState.skuDataList||[])[0],
|
||||
chosen:(a.formState.skuAttrs||[]).map(x=>({name:x.name, vals:(x.attributeValues||[]).map(v=>v.attribute_value||v)}))},null,1);})()`);
|
||||
console.log(String(o).slice(0,1800));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,34 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
// 打开主规格颜色下拉
|
||||
const pos = JSON.parse(String(await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/主规格/.test(l.innerText||'');});
|
||||
const s=it.querySelector('.ant-select-selector'); s.scrollIntoView({block:'center'});
|
||||
const r=s.getBoundingClientRect(); return JSON.stringify([Math.round(r.x+r.width/2),Math.round(r.y+r.height/2)]);})()`)));
|
||||
for(const t of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type:t,x:pos[0],y:pos[1],button:'left',clickCount:1});
|
||||
await wait(3000);
|
||||
const opts = await c.evalJS(`(()=>{const dd=[...document.querySelectorAll('.ant-select-dropdown')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!dd)return'no-dd'; const its=[...dd.querySelectorAll('.ant-select-item-option')];
|
||||
return JSON.stringify({n:its.length, first:its.slice(0,6).map(e=>(e.innerText||'').trim())});})()`);
|
||||
console.log('颜色选项:', String(opts).slice(0,400));
|
||||
// 选 Multicolor / Black(找不到就第一个)
|
||||
const pick = await c.evalJS(`(()=>{const dd=[...document.querySelectorAll('.ant-select-dropdown')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!dd)return'no-dd'; const its=[...dd.querySelectorAll('.ant-select-item-option')];
|
||||
let hit=its.find(o=>/Multicolor|Multi-color/i.test(o.innerText||'')) || its.find(o=>/^\\s*Black\\(/.test((o.innerText||'').trim())) || its[0];
|
||||
if(!hit)return'no-opt';
|
||||
for(const ev of ['mousedown','mouseup','click']) hit.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window}));
|
||||
return 'picked:'+(hit.innerText||'').trim();})()`);
|
||||
console.log('选择:', pick);
|
||||
await wait(6000);
|
||||
const o = await c.evalJS(`(()=>{
|
||||
const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const tbls=[...document.querySelectorAll('table')].filter(t=>t.offsetParent!==null).map(t=>({
|
||||
th:[...t.querySelectorAll('th')].map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim()).slice(0,14),
|
||||
rows:[...t.querySelectorAll('tbody tr')].filter(x=>x.querySelectorAll('input').length).length}));
|
||||
const d=JSON.parse(JSON.stringify(p._s.get('sheinSkuDataStore').$state));
|
||||
const a=JSON.parse(JSON.stringify(p._s.get('sheinSkuAttrStore').$state));
|
||||
return JSON.stringify({tbls, skuDataList:(d.formState.skuDataList||[]).slice(0,2), n:(d.formState.skuDataList||[]).length,
|
||||
chosen:(a.formState.skuAttrs||[]).map(x=>({name:x.name, n:(x.attributeValues||x._chosen||[]).length}))},null,1);})()`);
|
||||
console.log(String(o).slice(0,1800));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,62 @@
|
||||
import { newTarget, CDP } from '/tmp/cdp3.mjs';
|
||||
import fs from 'fs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const SHOP = process.argv[2] || '③shein-易捷天宇-美妆';
|
||||
const CATKW = process.argv[3] || '发夹';
|
||||
const tl = await (await fetch('http://127.0.0.1:9223/json/list')).json();
|
||||
for (const t of tl.filter(x=>x.type==='page'&&/shein/i.test(x.url))) await fetch(`http://127.0.0.1:9223/json/close/${t.id}`).catch(()=>{});
|
||||
await wait(1000);
|
||||
const t = await newTarget('about:blank');
|
||||
const c = await CDP.connect(t.webSocketDebuggerUrl);
|
||||
await c.send('Page.enable'); await c.send('Runtime.enable');
|
||||
await c.send('Page.navigate',{url:'https://www.dianxiaomi.com/web/sheinProduct/add'});
|
||||
await wait(21000);
|
||||
// 店铺
|
||||
const pos = JSON.parse(String(await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/店铺/.test(l.innerText||'');});
|
||||
const s=(it||document).querySelector('.ant-select-selector'); s.scrollIntoView({block:'center'});
|
||||
const r=s.getBoundingClientRect(); return JSON.stringify([Math.round(r.x+r.width/2),Math.round(r.y+r.height/2)]);})()`)));
|
||||
for (const type of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type,x:pos[0],y:pos[1],button:'left',clickCount:1});
|
||||
await wait(2500);
|
||||
await c.evalJS(`(()=>{const dd=[...document.querySelectorAll('.ant-select-dropdown')].filter(e=>e.offsetParent!==null).pop();
|
||||
const hit=[...dd.querySelectorAll('.ant-select-item-option')].find(o=>(o.innerText||'').trim()===${JSON.stringify(SHOP)});
|
||||
if(hit) for(const ev of ['mousedown','mouseup','click']) hit.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return 1;})()`);
|
||||
await wait(8000);
|
||||
// 开分类下拉并选目标
|
||||
const cp = JSON.parse(String(await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/产品分类/.test(l.innerText||'');});
|
||||
const s=it.querySelector('.ant-select-selector'); s.scrollIntoView({block:'center'});
|
||||
const r=s.getBoundingClientRect(); return JSON.stringify([Math.round(r.x+r.width/2),Math.round(r.y+r.height/2)]);})()`)));
|
||||
for (const type of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type,x:cp[0],y:cp[1],button:'left',clickCount:1});
|
||||
await wait(3500);
|
||||
const pk = await c.evalJS(`(()=>{const dd=[...document.querySelectorAll('.ant-select-dropdown')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!dd)return'no-dd'; const its=[...dd.querySelectorAll('.ant-select-item-option')];
|
||||
const hit=its.find(o=>new RegExp('^\\\\s*'+${JSON.stringify(CATKW)}).test((o.innerText||'').trim()));
|
||||
if(!hit)return'no-hit:'+its.slice(0,5).map(o=>o.innerText.trim()).join(',');
|
||||
for(const ev of ['mousedown','mouseup','click']) hit.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window}));
|
||||
return 'picked:'+(hit.innerText||'').trim();})()`);
|
||||
console.log('类目:', pk);
|
||||
await wait(12000);
|
||||
const o = await c.evalJS(`(()=>{
|
||||
const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const items=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null).map(x=>{
|
||||
const l=x.querySelector('label'); const lab=l?(l.innerText||'').replace(/\\s+/g,' ').trim():'';
|
||||
const req=!!x.querySelector('.ant-form-item-required');
|
||||
const inp=x.querySelector('input:not([type=hidden])'); const ta=x.querySelector('textarea'); const sel=x.querySelector('.ant-select-selection-item');
|
||||
return (req?'* ':' ')+lab.slice(0,24).padEnd(25)+'['+(ta?'ta':(sel?'select':(inp?'input':'-')))+'] '+(sel?sel.innerText.trim():(inp?inp.value:(ta?ta.value:''))).slice(0,22);
|
||||
}).filter(x=>x.trim().length>4);
|
||||
const tables=[...document.querySelectorAll('table')].filter(t=>t.offsetParent!==null).map(t=>({
|
||||
th:[...t.querySelectorAll('th')].map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim()).slice(0,12),
|
||||
rows:[...t.querySelectorAll('tbody tr')].filter(x=>x.querySelectorAll('input').length).length}));
|
||||
const cut=(x,d=0)=>(d>3?'…':(Array.isArray(x)?(x.length?'['+x.length+'] '+JSON.stringify(x[0]).slice(0,220):'[]'):(x&&typeof x==='object'?Object.fromEntries(Object.entries(x).map(([k,v])=>[k,cut(v,d+1)])):x)));
|
||||
const dump={};
|
||||
for(const n of ['sheinAddProductStore','sheinSkuDataStore','sheinSkuAttrStore','sheinAddBasicStore','sheinImgStore'])
|
||||
{ try{dump[n]=cut(JSON.parse(JSON.stringify(p._s.get(n).$state)));}catch(e){dump[n]='ERR';} }
|
||||
return JSON.stringify({items, tables, dump},null,1);})()`);
|
||||
fs.writeFileSync('/tmp/shein_deep.json', String(o));
|
||||
const j=JSON.parse(String(o));
|
||||
console.log('=== form ==='); j.items.forEach(x=>console.log(' '+x));
|
||||
console.log('=== tables ==='); console.log(JSON.stringify(j.tables));
|
||||
console.log('=== stores ===');
|
||||
for(const [n,v] of Object.entries(j.dump)) console.log(' ##',n,JSON.stringify(v).slice(0,520));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,189 @@
|
||||
{
|
||||
"items": [
|
||||
"* 店铺账号 [select] ③shein-易捷天宇-美妆",
|
||||
"* 产品分类 [select] 发夹(Hair Clips)",
|
||||
" 产品属性 [select] No(否)",
|
||||
" 品牌 [input] ",
|
||||
" 是否含木质材料 (Whether it cont [select] No(否)",
|
||||
" 敏感类别 (Hazard Category) [input] ",
|
||||
" 关税种类 (Tariff Type) [select] Hairpin(发夹)",
|
||||
" 材质 (Material) [select] Zinc Alloy(锌合金)",
|
||||
" 风格 (Style) [input] ",
|
||||
" 数量 (Quantity) [select] piece(s)(件)",
|
||||
" 季节 (Season) [input] ",
|
||||
" 细化图案 (Specific Pattern) [input] ",
|
||||
" 类型 (Type) [input] ",
|
||||
" 特征 (Features) [input] ",
|
||||
" 证书编号/检测机构 (Certificate N [input] ",
|
||||
" 是否有型号 (Is there a Model [input] ",
|
||||
" 电池使用方式 (Battery Usage Ty [input] ",
|
||||
" 版型 (Version) [input] ",
|
||||
" 包装类型 (type of packaging) [input] ",
|
||||
" 成分 (Composition) [input] ",
|
||||
" 次要材质 (Other Material) [input] ",
|
||||
" 发圈类型 (hair tie type) [input] ",
|
||||
" 元素 (Element) [select] None(无)",
|
||||
" 制作工艺 (Craftsmanship Type [input] ",
|
||||
" 企划风格 (Design Style) [input] ",
|
||||
" 产品型号 (Product Model) [input] ",
|
||||
" 镀贵金属类型 (Plating) [input] ",
|
||||
" 镶嵌类型 (Inlay type) [input] ",
|
||||
" 织造方式 (Fabric Weave Type) [input] ",
|
||||
" NCM-BR专属 (Ncm-Br Exclusi [input] ",
|
||||
" 系列 (Series) [input] ",
|
||||
" 是否多套件 [-] ",
|
||||
" 店小秘分类 [-] ",
|
||||
" 来源URL [input] ",
|
||||
" [input] ",
|
||||
"* 产品标题: [input] ",
|
||||
" 商品IP [input] ",
|
||||
" 图片模式 [input] 1",
|
||||
" 产品视频 [select] SHEIN国际站",
|
||||
"* 主规格 [select] 颜色(Color)",
|
||||
" 其他规格 [-] ",
|
||||
"* 尺码表 [-] "
|
||||
],
|
||||
"tables": [],
|
||||
"dump": {
|
||||
"sheinAddProductStore": {
|
||||
"formState": {
|
||||
"imageType": 0,
|
||||
"productName": ""
|
||||
},
|
||||
"dataState": {
|
||||
"newSizeGroups": "[]",
|
||||
"newBootSizeGroups": "[]"
|
||||
}
|
||||
},
|
||||
"sheinSkuDataStore": {
|
||||
"formState": {
|
||||
"identifierCodeType": 1,
|
||||
"supplierType": "EAN",
|
||||
"skuDataList": "[]",
|
||||
"deleteCombinationSkus": "[]",
|
||||
"siteTableInfoData": "[]",
|
||||
"sampleInfoObj": {
|
||||
"sampleJudgeType": "2",
|
||||
"reserveSampleFlag": "2",
|
||||
"spotFlag": "1"
|
||||
}
|
||||
},
|
||||
"dataState": {
|
||||
"skcRetailPriceEdit": true,
|
||||
"stockEdit": true,
|
||||
"specialPriceEdit": true,
|
||||
"supplyPriceEdit": true,
|
||||
"priceEdit": true
|
||||
},
|
||||
"siteStockStr": "_stock",
|
||||
"recordMainVariant": {}
|
||||
},
|
||||
"sheinSkuAttrStore": {
|
||||
"formState": {
|
||||
"skuAttrs": "[1] {\"attributeId\":27,\"name\":\"颜色\",\"nameEn\":\"Color\",\"_options\":[{\"attribute_value\":\"Apricot\",\"attribute_value_en\":\"Apricot\",\"attribute_value_id\":78,\"is_show\":1,\"supplier_id\":0,\"attribute_value_cn\":\"杏色\"},{\"attribute_value\":\"Be",
|
||||
"sizeTableInfo": "[]"
|
||||
},
|
||||
"dataState": {
|
||||
"mainVariantId": 27,
|
||||
"mainVariantList": "[1] {\"id\":4810372362706115,\"puid\":70000,\"shopId\":6226408,\"categoryId\":0,\"productTypeId\":603,\"businessMode\":\"5\",\"attributeId\":27,\"name\":\"颜色\",\"nameEn\":\"Color\",\"show\":1,\"label\":1,\"mode\":2,\"source\":1,\"status\":3,\"type\":1,\"dimensi",
|
||||
"variantList": "[3] {\"id\":4810372362706123,\"puid\":70000,\"shopId\":6226408,\"categoryId\":0,\"productTypeId\":603,\"businessMode\":\"5\",\"attributeId\":87,\"name\":\"尺寸\",\"nameEn\":\"Size\",\"show\":1,\"label\":0,\"mode\":2,\"source\":1,\"status\":3,\"type\":1,\"dimensio",
|
||||
"isHasSizeChart": true,
|
||||
"cacheIsHasSizeChart": true,
|
||||
"sizeTableData": "[6] {\"id\":4810372362706189,\"puid\":70000,\"shopId\":6226408,\"categoryId\":0,\"productTypeId\":603,\"businessMode\":\"5\",\"attributeId\":55,\"name\":\"长度 (cm)\",\"nameEn\":\"Length (cm)\",\"show\":1,\"label\":0,\"mode\":0,\"source\":1,\"status\":3,\"type\"",
|
||||
"isAllowEditSkcData": "[]",
|
||||
"collectDetailImages": ""
|
||||
},
|
||||
"customAttrOptions": {
|
||||
"27": "[]"
|
||||
},
|
||||
"recordData": {
|
||||
"oldOption": "[]",
|
||||
"newOption": "[]"
|
||||
}
|
||||
},
|
||||
"sheinAddBasicStore": {
|
||||
"formState": {
|
||||
"shopId": "6226408",
|
||||
"categoryId": 2734
|
||||
},
|
||||
"shopList": "[11] {\"id\":5986682,\"puid\":70000,\"name\":\"⑧Shein-易世通达-文具\",\"apiKey\":null,\"merchantId\":\"14349C4899B04FE59CECE6A4EA6CDB9C\",\"merchantUserName\":\"2\",\"awsAccessKeyId\":\"zh-cn|CNY\",\"marketPlaceId\":\"4328424\",\"lastSyncTimeProduct\":null,\"l",
|
||||
"dataState": {
|
||||
"categories": "[67] {\"id\":4810372411213177,\"puid\":70000,\"shopId\":6226408,\"categoryId\":2735,\"productTypeId\":604,\"parentId\":2732,\"name\":\"发爪\",\"nameEn\":\"Hair Claws\",\"nodePath\":\"服饰装饰品(Apparel Accessories)/女士配饰(Women Accessories)/女士发饰(Women Hair ",
|
||||
"categoryPathName": "服饰装饰品(Apparel Accessories) > 女士配饰(Women Accessories) > 女士发饰(Women Hair Accessories) > 发夹(Hair Clips)",
|
||||
"shopIds": "[1] \"6226408\"",
|
||||
"euSiteList": "[]",
|
||||
"shopSiteList": "[57] {\"id\":4810364349509615,\"puid\":70000,\"shopId\":6226408,\"currency\":\"USD\",\"siteAbbr\":\"shein-www\",\"siteName\":\"SHEIN国际站\",\"mainSite\":\"shein\",\"mainSiteName\":\"SHEIN\",\"storeType\":0,\"symbolLeft\":\"$\",\"symbolRight\":\"\",\"rateInfo\":\"[{\\",
|
||||
"warehouseList": "[]",
|
||||
"euSiteStockShopList": "[]",
|
||||
"categoryUpdated": false
|
||||
},
|
||||
"currencyCode": "CNY",
|
||||
"isEurSite": false,
|
||||
"isAllowEditOnlineProductFlag": false,
|
||||
"infoDisplayRules": {
|
||||
"image_module_show": true,
|
||||
"reference_module_show": false,
|
||||
"allow_switch_spu_picture": true,
|
||||
"sample_spec_show": false,
|
||||
"sample_spec_required": false,
|
||||
"minimum_stock_quantity_show": false,
|
||||
"minimum_stock_quantity_required": false,
|
||||
"reference_product_link_show": false,
|
||||
"reference_product_link_required": false,
|
||||
"proof_of_stock_show": false,
|
||||
"proof_of_stock_required": false,
|
||||
"skc_retail_price_show": true,
|
||||
"skc_retail_price_required": false,
|
||||
"quantity_info_show": true,
|
||||
"quantity_info_required": false,
|
||||
"package_type_show": true,
|
||||
"package_type_required": false,
|
||||
"supplier_barcode_show": false,
|
||||
"supplier_barcode_required": false,
|
||||
"goods_ip_show": true,
|
||||
"goods_ip_required": false,
|
||||
"product_video_show": true,
|
||||
"product_video_required": false,
|
||||
"shelf_require_show": true,
|
||||
"shelf_require_required": false,
|
||||
"title_max_length": 150
|
||||
},
|
||||
"imageDisplayRules": {
|
||||
"switch_spu_picture": false,
|
||||
"spu_image_detail_show": false,
|
||||
"spu_image_detail_required": false,
|
||||
"spu_image_detail_single": false,
|
||||
"spu_image_square_show": false,
|
||||
"spu_image_square_required": false,
|
||||
"skc_image_detail_show": true,
|
||||
"skc_image_detail_required": true,
|
||||
"skc_image_detail_single": false,
|
||||
"skc_image_square_show": true,
|
||||
"skc_image_square_required": true,
|
||||
"sku_image_detail_show": true,
|
||||
"sku_image_detail_required": false,
|
||||
"package_type_show": false,
|
||||
"package_type_required": false,
|
||||
"supplier_barcode_show": false,
|
||||
"supplier_barcode_required": false,
|
||||
"shelf_require_show": false,
|
||||
"shelf_require_required": false,
|
||||
"title_max_length": 1000
|
||||
},
|
||||
"isMxSite": false,
|
||||
"isJapanSite": false,
|
||||
"isKoreanSite": false
|
||||
},
|
||||
"sheinImgStore": {
|
||||
"formState": {
|
||||
"mainImgData": {
|
||||
"multipleSpuImgs": "[]"
|
||||
}
|
||||
},
|
||||
"dataState": {
|
||||
"newSizeGroups": "[]",
|
||||
"newBootSizeGroups": "[]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"stores": [
|
||||
"sheinAddStore",
|
||||
"sheinAddProductStore",
|
||||
"sheinSkuDataStore",
|
||||
"sheinSkuAttrStore",
|
||||
"sheinAddBasicStore",
|
||||
"sheinAddOtherStore",
|
||||
"sheinQualoficaStore",
|
||||
"sheinProductVideoStore",
|
||||
"sheinImgStore"
|
||||
],
|
||||
"items": [
|
||||
"* 店铺账号 [select] ①Shein-武汉九个网-箱包",
|
||||
"* 产品分类 [input] ",
|
||||
" 是否多套件 [-] ",
|
||||
" 店小秘分类 [-] ",
|
||||
" 来源URL [input] ",
|
||||
" [input] ",
|
||||
"* 产品标题: [input] ",
|
||||
" 图片模式 [input] 1"
|
||||
],
|
||||
"dump": {
|
||||
"sheinAddStore": {
|
||||
"attrsInfo.showSizeAttr": "false",
|
||||
"sharedData.isFeedBacking": "false",
|
||||
"sharedData.isAllowEditOnline": "false",
|
||||
"sharedData.variantImageNum": "0",
|
||||
"dataState.isVip": "true"
|
||||
},
|
||||
"sheinAddProductStore": {
|
||||
"formState.imageType": "0"
|
||||
},
|
||||
"sheinSkuDataStore": {
|
||||
"formState.identifierCodeType": "1",
|
||||
"formState.supplierType": "EAN",
|
||||
"dataState.skcRetailPriceEdit": "true",
|
||||
"dataState.stockEdit": "true",
|
||||
"dataState.specialPriceEdit": "true",
|
||||
"dataState.supplyPriceEdit": "true",
|
||||
"dataState.priceEdit": "true",
|
||||
"siteStockStr": "_stock"
|
||||
},
|
||||
"sheinSkuAttrStore": {
|
||||
"dataState.isHasSizeChart": "false",
|
||||
"dataState.cacheIsHasSizeChart": "false"
|
||||
},
|
||||
"sheinAddBasicStore": {
|
||||
"formState.shopId": "6229819",
|
||||
"dataState.categoryUpdated": "false",
|
||||
"currencyCode": "CNY",
|
||||
"isEurSite": "false",
|
||||
"isAllowEditOnlineProductFlag": "false",
|
||||
"infoDisplayRules.image_module_show": "false",
|
||||
"infoDisplayRules.reference_module_show": "false",
|
||||
"infoDisplayRules.allow_switch_spu_picture": "false",
|
||||
"infoDisplayRules.sample_spec_show": "false",
|
||||
"infoDisplayRules.sample_spec_required": "false",
|
||||
"infoDisplayRules.minimum_stock_quantity_show": "false",
|
||||
"infoDisplayRules.minimum_stock_quantity_required": "false",
|
||||
"infoDisplayRules.reference_product_link_show": "false",
|
||||
"infoDisplayRules.reference_product_link_required": "false",
|
||||
"infoDisplayRules.proof_of_stock_show": "false",
|
||||
"infoDisplayRules.proof_of_stock_required": "false",
|
||||
"infoDisplayRules.skc_retail_price_show": "false",
|
||||
"infoDisplayRules.skc_retail_price_required": "false",
|
||||
"infoDisplayRules.quantity_info_show": "false",
|
||||
"infoDisplayRules.quantity_info_required": "false",
|
||||
"infoDisplayRules.package_type_show": "false",
|
||||
"infoDisplayRules.package_type_required": "false",
|
||||
"infoDisplayRules.supplier_barcode_show": "false",
|
||||
"infoDisplayRules.supplier_barcode_required": "false",
|
||||
"infoDisplayRules.goods_ip_show": "false",
|
||||
"infoDisplayRules.goods_ip_required": "false",
|
||||
"infoDisplayRules.product_video_show": "false",
|
||||
"infoDisplayRules.product_video_required": "false",
|
||||
"infoDisplayRules.shelf_require_show": "false",
|
||||
"infoDisplayRules.shelf_require_required": "false",
|
||||
"infoDisplayRules.title_max_length": "1000",
|
||||
"imageDisplayRules.switch_spu_picture": "false",
|
||||
"imageDisplayRules.spu_image_detail_show": "false",
|
||||
"imageDisplayRules.spu_image_detail_required": "false",
|
||||
"imageDisplayRules.spu_image_detail_single": "false",
|
||||
"imageDisplayRules.spu_image_square_show": "false",
|
||||
"imageDisplayRules.spu_image_square_required": "false",
|
||||
"imageDisplayRules.skc_image_detail_show": "true",
|
||||
"imageDisplayRules.skc_image_detail_required": "true",
|
||||
"imageDisplayRules.skc_image_detail_single": "false",
|
||||
"imageDisplayRules.skc_image_square_show": "true",
|
||||
"imageDisplayRules.skc_image_square_required": "true",
|
||||
"imageDisplayRules.sku_image_detail_show": "true",
|
||||
"imageDisplayRules.sku_image_detail_required": "false",
|
||||
"imageDisplayRules.package_type_show": "false",
|
||||
"imageDisplayRules.package_type_required": "false",
|
||||
"imageDisplayRules.supplier_barcode_show": "false",
|
||||
"imageDisplayRules.supplier_barcode_required": "false",
|
||||
"imageDisplayRules.shelf_require_show": "false",
|
||||
"imageDisplayRules.shelf_require_required": "false",
|
||||
"imageDisplayRules.title_max_length": "1000",
|
||||
"isMxSite": "false",
|
||||
"isJapanSite": "false",
|
||||
"isKoreanSite": "false"
|
||||
},
|
||||
"sheinAddOtherStore": {},
|
||||
"sheinQualoficaStore": {
|
||||
"formData.isGrayShow": "false",
|
||||
"formData.isShow": "false"
|
||||
},
|
||||
"sheinProductVideoStore": {
|
||||
"dataState.supported": "false"
|
||||
},
|
||||
"sheinImgStore": {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"美妆": {
|
||||
"shop": "③shein-易捷天宇-美妆",
|
||||
"kw": {
|
||||
"661190598139": "大肠圈",
|
||||
"902440558099": "大肠圈",
|
||||
"823560564174": "大肠圈",
|
||||
"607330049419": "大肠圈",
|
||||
"854003999648": "大肠圈",
|
||||
"735147938123": "发箍",
|
||||
"610164857063": "发箍",
|
||||
"833753630925": "发箍",
|
||||
"676236596821": "发夹",
|
||||
"944470567338": "发夹",
|
||||
"787261097583": "发夹",
|
||||
"857781294719": "发夹",
|
||||
"863384503032": "发夹",
|
||||
"726442972676": "发夹",
|
||||
"893592264148": "发夹",
|
||||
"836512561982": "化妆包",
|
||||
"714492799386": "化妆包",
|
||||
"719391062058": "化妆包"
|
||||
}
|
||||
},
|
||||
"文具": {
|
||||
"shop": "⑥Shein-南京亿千-文具",
|
||||
"kw": {
|
||||
"953869908708": "涂鸦贴纸",
|
||||
"863524134410": "涂鸦贴纸",
|
||||
"623011262210": "涂鸦贴纸",
|
||||
"997450831819": "涂鸦贴纸",
|
||||
"639409307567": "涂鸦贴纸",
|
||||
"698782391248": "涂鸦贴纸",
|
||||
"591994902720": "笔袋",
|
||||
"682195499823": "笔袋",
|
||||
"657617635303": "回形针",
|
||||
"703822717997": "回形针",
|
||||
"621300323670": "桌面摆件",
|
||||
"823838532886": "卡套",
|
||||
"1027332215847": "文具收纳盒"
|
||||
}
|
||||
},
|
||||
"箱包": {
|
||||
"shop": "①Shein-武汉九个网-箱包",
|
||||
"kw": {
|
||||
"641673262387": "其他收纳包",
|
||||
"707826905566": "卡包",
|
||||
"694637537727": "保温午餐包",
|
||||
"708420302844": "包包挂件",
|
||||
"750271307455": "包包挂件",
|
||||
"774494945453": "包包挂件",
|
||||
"775057912118": "包包挂件",
|
||||
"896469995553": "包包挂件"
|
||||
}
|
||||
},
|
||||
"内睡袜子": {
|
||||
"shop": "⑤Shein-惠州九衢-内睡(袜子)",
|
||||
"kw": {
|
||||
"627879474686": "袜子"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
const reqs=[];
|
||||
c.on(m=>{ if(m.method==='Network.requestWillBeSent'){const r=m.params.request;
|
||||
if(/shein/i.test(r.url)&&/\.json/.test(r.url)&&r.method==='POST') reqs.push(r.url.replace('https://www.dianxiaomi.com','')); }});
|
||||
await c.send('Network.enable').catch(()=>{});
|
||||
const IMGS=['https://cbu01.alicdn.com/img/ibank/O1CN01IHtNAHKMzNC1chua_!!2222444614399-0-cib.jpg',
|
||||
'https://cbu01.alicdn.com/img/ibank/O1CN01UGEWafTzqTH1chua_!!2222444614399-0-cib.jpg',
|
||||
'https://cbu01.alicdn.com/img/ibank/O1CN01d0hA4N72jzD1chua_!!2222444614399-0-cib.jpg',
|
||||
'https://cbu01.alicdn.com/img/ibank/O1CN01edgGxIlmdtJ1chua_!!2222444614399-0-cib.jpg'];
|
||||
const r = await c.evalJS(`(()=>{const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const d=p._s.get('sheinSkuDataStore').$state.formState;
|
||||
const rows=d.skuDataList||[]; let n=0;
|
||||
rows.forEach((x,i)=>{ x.skcSupplierCode='SHEIN-TEST-'+(i+1); x.skcRetailPrice='12.90'; x.supplyPrice='8.50';
|
||||
x.stockVariety='999'; x.weight='100'; x.length='200'; x.width='150'; x.height='30'; n++; });
|
||||
const im=p._s.get('sheinImgStore').$state.formState;
|
||||
im.mainImgData.multipleSpuImgs=${JSON.stringify(IMGS.map((u,i)=>({url:u,imgUrl:u,name:'img'+(i+1)+'.jpg',width:800,height:800})))};
|
||||
return JSON.stringify({rows:n, imgs:im.mainImgData.multipleSpuImgs.length, imgType:Array.isArray(im.mainImgData.multipleSpuImgs)?'array':typeof im.mainImgData.multipleSpuImgs});})()`);
|
||||
console.log('填充:', r);
|
||||
await wait(3500);
|
||||
const chk = await c.evalJS(`(()=>{const it=[...document.querySelectorAll('*')].filter(e=>e.offsetParent!==null&&/图片/.test(e.innerText||'')&&e.querySelectorAll('img').length>0);
|
||||
return JSON.stringify({domImgs:it.length?it[0].querySelectorAll('img').length:0});})()`);
|
||||
console.log('UI 图片:', String(chk));
|
||||
await c.evalJS(`window.scrollTo(0,0)`); await wait(600);
|
||||
const sv = await c.evalJS(`(()=>{const xs=[...document.querySelectorAll('button')].filter(e=>e.offsetParent!==null);
|
||||
let x=xs.find(e=>/^\\s*保存\\s*$/.test((e.innerText||'').trim()))||xs.find(e=>/保存/.test(e.innerText||''));
|
||||
if(!x)return'nf'; for(const ev of ['mousedown','mouseup','click']) x.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return (x.innerText||'').trim();})()`);
|
||||
console.log('保存按钮:', sv);
|
||||
await wait(13000);
|
||||
await c.evalJS(`(()=>{const ms=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null);
|
||||
for(const m of ms){const b=[...m.querySelectorAll('button')].find(x=>/确定|确认/.test(x.innerText||'')); if(b)b.click();} return 1;})()`);
|
||||
await wait(4000);
|
||||
console.log('POST 请求:', JSON.stringify([...new Set(reqs)].slice(0,5)));
|
||||
const red = await c.evalJS(`(()=>{const red=[]; document.querySelectorAll('*').forEach(el=>{ if(el.offsetParent===null||el.children.length)return;
|
||||
const t=(el.innerText||'').trim(); if(!t||t.length>60)return;
|
||||
const s=getComputedStyle(el); const m=(s.color||'').match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/); if(!m)return;
|
||||
if(+m[1]>160&&+m[2]<140&&+m[3]<140) red.push(t); });
|
||||
const toasts=[...document.querySelectorAll('.ant-message-notice,.ant-notification-notice')].map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim());
|
||||
return JSON.stringify({red:[...new Set(red)].slice(0,10), toasts:[...new Set(toasts)].slice(0,3)});})()`);
|
||||
console.log('红字/提示:', String(red).slice(0,600));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,38 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
const reqs=[];
|
||||
c.on(m=>{ if(m.method==='Network.requestWillBeSent'){const r=m.params.request;
|
||||
if(/shein/i.test(r.url)&&/\.json/.test(r.url)&&r.method==='POST') reqs.push(r.url.replace('https://www.dianxiaomi.com','')); }});
|
||||
await c.send('Network.enable').catch(()=>{});
|
||||
// 两个规格组各点一个 .sku-option
|
||||
const r = await c.evalJS(`(()=>{const boxes=[...document.querySelectorAll('.sku-info-box')].filter(e=>e.offsetParent!==null);
|
||||
const done=[];
|
||||
boxes.forEach((b,i)=>{ const opts=[...b.querySelectorAll('.sku-option')].filter(e=>e.offsetParent!==null);
|
||||
if(!opts.length){done.push(i+':no-opt');return;}
|
||||
const inp=opts[0].querySelector('input[type=checkbox]');
|
||||
if(inp&&inp.checked){done.push(i+':already');return;}
|
||||
const lab=opts[0].querySelector('label')||opts[0];
|
||||
for(const ev of ['mousedown','mouseup','click']) lab.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window}));
|
||||
if(inp&&!inp.checked) inp.click();
|
||||
done.push(i+':'+(opts[0].innerText||'').trim().slice(0,18)); });
|
||||
return done.join(' | ');})()`);
|
||||
console.log('选规格值:', String(r));
|
||||
await wait(7000);
|
||||
const st = await c.evalJS(`(()=>{const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const a=JSON.parse(JSON.stringify(p._s.get('sheinSkuAttrStore').$state));
|
||||
const d=JSON.parse(JSON.stringify(p._s.get('sheinSkuDataStore').$state));
|
||||
return JSON.stringify({attrs:(a.formState.skuAttrs||[]).map(x=>({n:x.name, chosen:(x.options||[]).length})),
|
||||
skuRows:(d.formState.skuDataList||[]).length});})()`);
|
||||
console.log('状态:', String(st));
|
||||
// 保存
|
||||
await c.evalJS(`window.scrollTo(0,0)`); await wait(600);
|
||||
await c.evalJS(`(()=>{const x=[...document.querySelectorAll('button')].filter(e=>e.offsetParent!==null).find(e=>/^\\s*保存\\s*$/.test((e.innerText||'').trim()));
|
||||
if(x) for(const ev of ['mousedown','mouseup','click']) x.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return 1;})()`);
|
||||
await wait(12000);
|
||||
const cap = await c.evalJS(`JSON.stringify(window.__cap||[])`);
|
||||
console.log('捕获:', String(cap).slice(0,300));
|
||||
console.log('POST:', JSON.stringify([...new Set(reqs)].slice(0,3)));
|
||||
const t = await c.evalJS(`JSON.stringify([...document.querySelectorAll('.ant-message-notice,.ant-notification-notice,.ant-modal')].filter(e=>e.offsetParent!==null).map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim().slice(0,130)).filter(Boolean).slice(0,3))`);
|
||||
console.log('提示:', String(t).slice(0,400));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,60 @@
|
||||
import { newTarget, CDP } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const SHOP='③shein-易捷天宇-美妆', CATKW='发夹';
|
||||
const tl = await (await fetch('http://127.0.0.1:9223/json/list')).json();
|
||||
for (const x of tl.filter(y=>y.type==='page'&&/shein/i.test(y.url))) await fetch(`http://127.0.0.1:9223/json/close/${x.id}`).catch(()=>{});
|
||||
await wait(900);
|
||||
const nt = await newTarget('about:blank');
|
||||
const c = await CDP.connect(nt.webSocketDebuggerUrl);
|
||||
await c.send('Page.enable'); await c.send('Runtime.enable');
|
||||
await c.send('Page.navigate',{url:'https://www.dianxiaomi.com/web/sheinProduct/add'});
|
||||
await wait(21000);
|
||||
// 店铺
|
||||
const sp=JSON.parse(String(await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/店铺/.test(l.innerText||'');});
|
||||
const s=(it||document).querySelector('.ant-select-selector'); s.scrollIntoView({block:'center'});
|
||||
const r=s.getBoundingClientRect(); return JSON.stringify([Math.round(r.x+r.width/2),Math.round(r.y+r.height/2)]);})()`)));
|
||||
for(const t of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type:t,x:sp[0],y:sp[1],button:'left',clickCount:1});
|
||||
await wait(2400);
|
||||
await c.evalJS(`(()=>{const dd=[...document.querySelectorAll('.ant-select-dropdown')].filter(e=>e.offsetParent!==null).pop();
|
||||
const hit=[...dd.querySelectorAll('.ant-select-item-option')].find(o=>(o.innerText||'').trim()===${JSON.stringify(SHOP)});
|
||||
if(hit) for(const ev of ['mousedown','mouseup','click']) hit.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return 1;})()`);
|
||||
await wait(8000);
|
||||
// 类目
|
||||
const cp=JSON.parse(String(await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/产品分类/.test(l.innerText||'');});
|
||||
const s=it.querySelector('.ant-select-selector'); s.scrollIntoView({block:'center'});
|
||||
const r=s.getBoundingClientRect(); return JSON.stringify([Math.round(r.x+r.width/2),Math.round(r.y+r.height/2)]);})()`)));
|
||||
for(const t of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type:t,x:cp[0],y:cp[1],button:'left',clickCount:1});
|
||||
await wait(3500);
|
||||
console.log('类目:', String(await c.evalJS(`(()=>{const dd=[...document.querySelectorAll('.ant-select-dropdown')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!dd)return'no-dd'; const its=[...dd.querySelectorAll('.ant-select-item-option')];
|
||||
const hit=its.find(o=>new RegExp('^\\\\s*'+${JSON.stringify(CATKW)}).test((o.innerText||'').trim()));
|
||||
if(!hit)return'no-hit'; for(const ev of ['mousedown','mouseup','click']) hit.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window}));
|
||||
return (hit.innerText||'').trim();})()`)));
|
||||
await wait(12000);
|
||||
// 标题
|
||||
await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/产品标题/.test(l.innerText||'');});
|
||||
const el=it.querySelector('input:not([type=hidden])'); el.focus();
|
||||
Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,'value').set.call(el,'Test Hair Clip Set for Women Girls Daily Use Fashion Accessory');
|
||||
el.dispatchEvent(new Event('input',{bubbles:true})); el.dispatchEvent(new Event('change',{bubbles:true}));
|
||||
const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
p._s.get('sheinAddProductStore').$state.formState.productName='Test Hair Clip Set for Women Girls Daily Use Fashion Accessory';
|
||||
return 1;})()`);
|
||||
await wait(1500);
|
||||
// 选主规格颜色(取第一个可选值)—— 先看控件结构
|
||||
const mg = await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/主规格/.test(l.innerText||'');});
|
||||
if(!it)return'nf';
|
||||
const sels=[...it.querySelectorAll('.ant-select')].map(s=>({txt:(s.innerText||'').replace(/\\s+/g,' ').slice(0,40), cls:String(s.className).slice(0,50)}));
|
||||
const cbs=[...it.querySelectorAll('.ant-checkbox-wrapper,.ant-tag,[class*=tag]')].slice(0,6).map(e=>(e.innerText||'').trim().slice(0,16));
|
||||
return JSON.stringify({sels, cbs, html:it.innerHTML.slice(0,400)});})()`);
|
||||
console.log('主规格控件:', String(mg).slice(0,800));
|
||||
// 图片字段测试:数组 vs 字符串
|
||||
const imgTest = await c.evalJS(`(()=>{const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const im=p._s.get('sheinImgStore').$state.formState;
|
||||
const before=JSON.stringify(im).slice(0,120);
|
||||
return JSON.stringify({before});})()`);
|
||||
console.log('图片字段现状:', String(imgTest).slice(0,300));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,50 @@
|
||||
import { newTarget, CDP } from '/tmp/cdp3.mjs';
|
||||
import fs from 'fs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const SHOP = process.argv[2] || '①Shein-武汉九个网-箱包';
|
||||
const tl = await (await fetch('http://127.0.0.1:9223/json/list')).json();
|
||||
for (const t of tl.filter(x=>x.type==='page'&&/shein/i.test(x.url))) await fetch(`http://127.0.0.1:9223/json/close/${t.id}`).catch(()=>{});
|
||||
await wait(1200);
|
||||
const t = await newTarget('about:blank');
|
||||
const c = await CDP.connect(t.webSocketDebuggerUrl);
|
||||
await c.send('Page.enable'); await c.send('Runtime.enable');
|
||||
await c.send('Page.navigate',{url:'https://www.dianxiaomi.com/web/sheinProduct/add'});
|
||||
await wait(22000);
|
||||
// 选店铺
|
||||
const pos = JSON.parse(String(await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/店铺/.test(l.innerText||'');});
|
||||
const s=(it||document).querySelector('.ant-select-selector');
|
||||
if(!s)return'[]'; s.scrollIntoView({block:'center'}); const r=s.getBoundingClientRect();
|
||||
return JSON.stringify([Math.round(r.x+r.width/2),Math.round(r.y+r.height/2)]);})()`)));
|
||||
for (const type of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type,x:pos[0],y:pos[1],button:'left',clickCount:1});
|
||||
await wait(2500);
|
||||
const pk = await c.evalJS(`(()=>{const dd=[...document.querySelectorAll('.ant-select-dropdown')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!dd)return'no-dd'; const hit=[...dd.querySelectorAll('.ant-select-item-option')].find(o=>(o.innerText||'').trim()===${JSON.stringify(SHOP)});
|
||||
if(!hit)return'no-hit'; for(const ev of ['mousedown','mouseup','click']) hit.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return 'ok';})()`);
|
||||
console.log('选店铺:', pk, SHOP);
|
||||
await wait(9000);
|
||||
const o = await c.evalJS(`(()=>{
|
||||
const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const stores=[...p._s.keys()].filter(k=>/shein/i.test(k));
|
||||
const items=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null).map(x=>{
|
||||
const l=x.querySelector('label'); const lab=l?(l.innerText||'').replace(/\\s+/g,' ').trim():'';
|
||||
const req=!!x.querySelector('.ant-form-item-required');
|
||||
const inp=x.querySelector('input:not([type=hidden])'); const ta=x.querySelector('textarea'); const sel=x.querySelector('.ant-select-selection-item');
|
||||
return (req?'* ':' ')+lab.slice(0,26).padEnd(27)+'['+(ta?'ta':(sel?'select':(inp?'input':'-')))+'] '+(sel?sel.innerText.trim():(inp?inp.value:(ta?ta.value:''))).slice(0,26);
|
||||
}).filter(x=>x.trim().length>4);
|
||||
const dump={};
|
||||
for(const n of stores){ try{ const s=p._s.get(n).$state; const o2={};
|
||||
for(const k of Object.keys(s)){ const v=s[k];
|
||||
if(v===null||['string','number','boolean'].includes(typeof v)){ if(v!==''&&v!==null&&String(v).length<55) o2[k]=String(v); }
|
||||
else if(v&&typeof v==='object'&&!Array.isArray(v)){ for(const k2 of Object.keys(v)){ const v2=v[k2];
|
||||
if(v2===null||['string','number','boolean'].includes(typeof v2)){ if(v2!==''&&v2!==null&&String(v2).length<45) o2[k+'.'+k2]=String(v2); } } } }
|
||||
dump[n]=o2; }catch(e){ dump[n]='ERR'; } }
|
||||
return JSON.stringify({stores, items, dump},null,1);})()`);
|
||||
fs.writeFileSync('/tmp/shein_map.json', String(o));
|
||||
const j=JSON.parse(String(o));
|
||||
console.log('stores:', j.stores.join(', '));
|
||||
console.log('--- form ---'); j.items.forEach(x=>console.log(' '+x));
|
||||
console.log('--- store 关键字段 ---');
|
||||
for(const [n,v] of Object.entries(j.dump)){ const hit=Object.entries(v||{}).filter(([k])=>/shop|site|currency|cat|brand|price|weight/i.test(k));
|
||||
if(hit.length) console.log(' ##',n,hit.map(([k,val])=>k+'='+val).join(' | ').slice(0,320)); }
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,27 @@
|
||||
import { newTarget, CDP, SAN } from '/tmp/cdp3.mjs';
|
||||
const t=await newTarget('about:blank');
|
||||
const c=await CDP.connect(t.webSocketDebuggerUrl);
|
||||
await c.send('Page.enable'); await c.send('Runtime.enable'); await c.send('Network.enable');
|
||||
const caps=[];
|
||||
c.on(m=>{ if(m.method==='Network.requestWillBeSent' && /shop/i.test(m.params.request.url))
|
||||
caps.push({m:m.params.request.method,u:m.params.request.url.replace('https://www.dianxiaomi.com',''),p:String(m.params.request.postData||'').slice(0,150)}); });
|
||||
await c.send('Page.navigate',{url:'https://www.dianxiaomi.com/web/ozonProduct/draft'});
|
||||
await new Promise(r=>setTimeout(r,24000));
|
||||
for(let i=0;i<8;i++){
|
||||
const x=await c.evalJS(`(()=>{const v=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null);
|
||||
if(!v.length)return'n'; const b=v[0].querySelector('.ant-modal-close'); if(b){b.click();return'c';} return's';})()`);
|
||||
if(x==='n'){await new Promise(z=>setTimeout(z,900));continue;} if(x==='s')break;
|
||||
await new Promise(z=>setTimeout(z,1200));
|
||||
}
|
||||
console.log(' ══ 含 shop 的接口 ══');
|
||||
[...new Set(caps.map(x=>x.m+' '+x.u))].slice(0,10).forEach(x=>console.log(' '+x));
|
||||
// 直接调最可能的那个拿映射
|
||||
const r=await c.evalJS(`(async()=>{
|
||||
const u=( ${JSON.stringify(caps.map(x=>x.u).filter(x=>/shop/i.test(x)))} )[0];
|
||||
if(!u) return 'no-url';
|
||||
const res=await fetch(u,{headers:{'X-Requested-With':'XMLHttpRequest'}});
|
||||
const tx=await res.text();
|
||||
return u+' -> '+tx.slice(0,900);})()`, true);
|
||||
console.log('\n ══ 店铺列表内容 ══');
|
||||
console.log(' '+SAN(String(r)).slice(0,900));
|
||||
c.close();
|
||||
@@ -0,0 +1,45 @@
|
||||
import { newTarget, CDP } from '/tmp/cdp3.mjs';
|
||||
import fs from 'fs';
|
||||
const URLX = process.argv[2];
|
||||
const TAG = process.argv[3] || 'x';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const tl = await (await fetch('http://127.0.0.1:9223/json/list')).json();
|
||||
for (const t of tl.filter(x => x.type==='page' && x.url.includes(TAG))) await fetch(`http://127.0.0.1:9223/json/close/${t.id}`).catch(()=>{});
|
||||
await wait(1000);
|
||||
const t = await newTarget('about:blank');
|
||||
const c = await CDP.connect(t.webSocketDebuggerUrl);
|
||||
await c.send('Page.enable'); await c.send('Runtime.enable');
|
||||
await c.send('Page.navigate',{url:URLX});
|
||||
await wait(22000);
|
||||
console.log('URL:', await c.evalJS('location.href'));
|
||||
const loc = await c.evalJS(`(()=>{
|
||||
const items=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null);
|
||||
for(let i=0;i<items.length;i++){ const l=items[i].querySelector('label'); if(l&&/店铺/.test(l.innerText||'')){
|
||||
const s=items[i].querySelector('.ant-select'); if(s){ const r=s.getBoundingClientRect(); return JSON.stringify({i, label:l.innerText.trim(), x:Math.round(r.x+r.width/2), y:Math.round(r.y+r.height/2), cur:(s.querySelector('.ant-select-selection-item')||{}).innerText||''}); } } }
|
||||
const s=[...document.querySelectorAll('.ant-select')].filter(e=>e.offsetParent!==null)[0];
|
||||
if(!s) return 'no-select'; const r=s.getBoundingClientRect();
|
||||
return JSON.stringify({i:-1, label:'(第一个)', x:Math.round(r.x+r.width/2), y:Math.round(r.y+r.height/2), cur:''});})()`);
|
||||
console.log('店铺选择器:', loc);
|
||||
const L = JSON.parse(String(loc));
|
||||
if (L.x) {
|
||||
for (const type of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type,x:L.x,y:L.y,button:'left',clickCount:1});
|
||||
await wait(2500);
|
||||
const all = new Set();
|
||||
for (let i=0;i<20;i++){
|
||||
const got = await c.evalJS(`(()=>{const dd=[...document.querySelectorAll('.ant-select-dropdown')].filter(e=>e.offsetParent!==null);
|
||||
if(!dd.length)return'[]'; const d=dd[dd.length-1];
|
||||
return JSON.stringify([...d.querySelectorAll('.ant-select-item-option')].map(e=>(e.innerText||'').trim()).filter(Boolean));})()`);
|
||||
const arr=JSON.parse(String(got)); const before=all.size; arr.forEach(x=>all.add(x));
|
||||
await c.evalJS(`(()=>{const dd=[...document.querySelectorAll('.ant-select-dropdown')].filter(e=>e.offsetParent!==null);
|
||||
if(!dd.length)return 0; const d=dd[dd.length-1];
|
||||
const rc=d.querySelector('.rc-virtual-list-holder')||d; rc.scrollTop=rc.scrollTop+800; return rc.scrollTop;})()`);
|
||||
await wait(700);
|
||||
if (all.size===before && i>2) break;
|
||||
}
|
||||
const list=[...all];
|
||||
fs.writeFileSync('/tmp/shops_'+TAG+'.json', JSON.stringify(list,null,1));
|
||||
console.log('店铺数:', list.length);
|
||||
list.sort((a,b)=>a.localeCompare(b));
|
||||
list.forEach((n,i)=>console.log(' '+String(i+1).padStart(2)+'. '+n));
|
||||
}
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,32 @@
|
||||
import { CDP, SAN } from '/tmp/cdp3.mjs';
|
||||
const list=await (await fetch('http://127.0.0.1:9223/json/list')).json();
|
||||
const t=list.find(x=>x.type==='page'&&/dianxiaomi/.test(x.url));
|
||||
if(!t){console.log(' ❌');process.exit(0);}
|
||||
const c=await CDP.connect(t.webSocketDebuggerUrl);
|
||||
await c.send('Runtime.enable');
|
||||
const r=await c.evalJS(`(async()=>{
|
||||
const out=[];
|
||||
const cands=[['/api/ozonProduct/getShop.json','GET'],['/api/shop/getShopList.json','GET'],
|
||||
['/api/ozonProduct/shopList.json','GET'],['/api/ozonProduct/getAuthShopList.json','GET'],
|
||||
['/api/shop/list.json','GET'],['/api/ozonProduct/getShopList.json','POST']];
|
||||
for(const [u,m] of cands){
|
||||
try{
|
||||
const res=await Promise.race([
|
||||
fetch(u, m==='POST'?{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded','X-Requested-With':'XMLHttpRequest'},body:''}
|
||||
:{headers:{'X-Requested-With':'XMLHttpRequest'}}),
|
||||
new Promise((_,rj)=>setTimeout(()=>rj(new Error('to')),10000))]);
|
||||
const tx=await res.text();
|
||||
if(res.status===200 && !tx.includes('<!DOCTYPE')) out.push(u+' -> '+tx.slice(0,420));
|
||||
}catch(e){}
|
||||
}
|
||||
return JSON.stringify(out);})()`, true);
|
||||
const arr=JSON.parse(r);
|
||||
if(!arr.length) console.log(' 店铺接口都没找到');
|
||||
arr.forEach(x=>console.log(' ★ '+SAN(x).slice(0,420)));
|
||||
// 直接在页面上找店铺下拉里的映射
|
||||
const dom=await c.evalJS(`(()=>{
|
||||
const txt=document.body.innerText;
|
||||
const i=txt.indexOf('Yejet');
|
||||
return JSON.stringify({has:txt.includes('Yejet'), around:i>=0?txt.slice(Math.max(0,i-60),i+60).replace(/\\n/g,' | '):''});})()`);
|
||||
console.log('\n 页面含 Yejet:', SAN(dom).slice(0,220));
|
||||
c.close();
|
||||
@@ -0,0 +1,21 @@
|
||||
import { CDP, SAN } from '/tmp/cdp3.mjs';
|
||||
const list=await (await fetch('http://127.0.0.1:9223/json/list')).json();
|
||||
const t=list.find(x=>x.type==='page'&&/dianxiaomi/.test(x.url));
|
||||
if(!t){console.log(' ❌');process.exit(0);}
|
||||
const c=await CDP.connect(t.webSocketDebuggerUrl);
|
||||
await c.send('Runtime.enable');
|
||||
const r=await c.evalJS(`(async()=>{
|
||||
const out={};
|
||||
// userIn 里通常带店铺
|
||||
try{ const res=await fetch('/api/userIn.json',{headers:{'X-Requested-With':'XMLHttpRequest'}});
|
||||
const tx=await res.text(); out.userIn=tx.slice(0,1200); }catch(e){ out.userIn='ERR'; }
|
||||
// 页面上是否嵌了 shop 映射
|
||||
out.htmlHas4248777 = document.documentElement.innerHTML.includes('4248777');
|
||||
const m=document.documentElement.innerHTML.match(/.{0,80}4248777.{0,120}/g);
|
||||
out.ctx = m? m.slice(0,3).map(x=>x.replace(/\\s+/g,' ')) : [];
|
||||
return JSON.stringify(out);})()`, true);
|
||||
const d=JSON.parse(r);
|
||||
console.log(' userIn 片段:', SAN(String(d.userIn)).slice(0,600));
|
||||
console.log('\n HTML 含 4248777:', d.htmlHas4248777);
|
||||
(d.ctx||[]).forEach(x=>console.log(' 上下文: '+SAN(String(x)).slice(0,190)));
|
||||
c.close();
|
||||
@@ -0,0 +1,18 @@
|
||||
import { CDP, SAN } from '/tmp/cdp3.mjs';
|
||||
const list=await (await fetch('http://127.0.0.1:9223/json/list')).json();
|
||||
const t=list.find(x=>x.type==='page'&&/dianxiaomi/.test(x.url));
|
||||
if(!t){console.log(' ❌');process.exit(0);}
|
||||
const c=await CDP.connect(t.webSocketDebuggerUrl);
|
||||
await c.send('Runtime.enable');
|
||||
const r=await c.evalJS(`(async()=>{
|
||||
const j=await (await fetch('/api/userIn.json',{headers:{'X-Requested-With':'XMLHttpRequest'}})).json();
|
||||
const sm=(j.data||{}).shopMap||{};
|
||||
const rows=Object.keys(sm).map(k=>({id:k, name:String(sm[k].name||''), plat:String(sm[k].platform||sm[k].site||'')}));
|
||||
const target=rows.find(x=>x.id==='4248777');
|
||||
return JSON.stringify({n:rows.length, target, yejet:rows.filter(x=>/yejet/i.test(x.name)).slice(0,8)});})()`, true);
|
||||
const d=JSON.parse(r);
|
||||
console.log(' shopMap 共', d.n, '个店铺');
|
||||
console.log(' ══ shopId=4248777 是 ══');
|
||||
console.log(' ', SAN(JSON.stringify(d.target)).slice(0,220));
|
||||
console.log('\n 名称含 yejet 的店铺:', SAN(JSON.stringify(d.yejet)).slice(0,300));
|
||||
c.close();
|
||||
@@ -0,0 +1,40 @@
|
||||
import { attach, SAN } from '/tmp/cdp3.mjs';
|
||||
const c = await attach('/web/ozonProduct/draft') || await attach('dianxiaomi.com');
|
||||
if(!c){ console.log('✗ 无页面'); process.exit(1); }
|
||||
await c.send('Runtime.enable');
|
||||
const r = await c.evalJS(`(async()=>{
|
||||
const rr = await fetch('/api/userInfo.json?_t='+Date.now(), {headers:{'X-Requested-With':'XMLHttpRequest'}});
|
||||
const tx = await rr.text();
|
||||
if(!tx.startsWith('{')) return JSON.stringify({err:'notjson', head:tx.slice(0,120)});
|
||||
const j = JSON.parse(tx); const d = j.data||{};
|
||||
const out = { topKeys: Object.keys(d) };
|
||||
// shopMap 结构
|
||||
const sm = d.shopMap || d.shops || {};
|
||||
out.shopMapType = Array.isArray(sm)?'array':typeof sm;
|
||||
if (Array.isArray(sm)) {
|
||||
out.shops = sm.map(s=>({id:s.id, idStr:s.idStr, name:s.name||s.shopName, platform:s.platform||s.platformName, site:s.site}));
|
||||
} else {
|
||||
out.shopMapKeys = Object.keys(sm).slice(0,40);
|
||||
out.shops = [];
|
||||
for (const [k,v] of Object.entries(sm)) {
|
||||
if (Array.isArray(v)) v.forEach(s=>out.shops.push({platform:k, id:s.id, idStr:s.idStr, name:s.name||s.shopName, site:s.site}));
|
||||
else if (v && typeof v === 'object') out.shops.push({platform:k, id:v.id, idStr:v.idStr, name:v.name||v.shopName});
|
||||
}
|
||||
}
|
||||
// 平台列表
|
||||
out.platformList = d.platformList || d.platforms || d.shopPlatformList || null;
|
||||
return JSON.stringify(out);
|
||||
})()`, true);
|
||||
try{
|
||||
const d = JSON.parse(String(r));
|
||||
if (d.err) { console.log(' ✗', d.err, d.head); process.exit(0); }
|
||||
console.log(' userInfo 顶层字段:', (d.topKeys||[]).join(', ').slice(0,300));
|
||||
console.log(' shopMap 类型:', d.shopMapType);
|
||||
if (d.shopMapKeys) console.log(' shopMap 键(平台):', d.shopMapKeys.join(', '));
|
||||
console.log();
|
||||
console.log(' ── 全部店铺 ──');
|
||||
(d.shops||[]).forEach(s=>console.log(' ', String(s.platform).padEnd(16), 'id='+String(s.id||s.idStr).padEnd(12), s.name||''));
|
||||
if (d.platformList) console.log();
|
||||
if (d.platformList) console.log(' platformList:', SAN(JSON.stringify(d.platformList)).slice(0,400));
|
||||
}catch(e){ console.log('err', e.message, SAN(String(r)).slice(0,600)); }
|
||||
c.close();
|
||||
@@ -0,0 +1,43 @@
|
||||
import { attach, SAN } from '/tmp/cdp3.mjs';
|
||||
const c = await attach('/web/ozonProduct/draft') || await attach('dianxiaomi.com');
|
||||
await c.send('Runtime.enable');
|
||||
const r = await c.evalJS(`(async()=>{
|
||||
const rr = await fetch('/api/userInfo.json?_t='+Date.now(), {headers:{'X-Requested-With':'XMLHttpRequest'}});
|
||||
const d = JSON.parse(await rr.text()).data;
|
||||
const out = {};
|
||||
// shopMap 一个条目的完整结构
|
||||
const sm = d.shopMap||{};
|
||||
const firstKey = Object.keys(sm)[0];
|
||||
out.shopMapSample = JSON.stringify(sm[firstKey]).slice(0, 400);
|
||||
// shopSmtTypeMap
|
||||
out.smtTypeMap = JSON.stringify(d.shopSmtTypeMap||{}).slice(0, 400);
|
||||
out.smtShopId = String(d.smtShopId);
|
||||
out.shopId = String(d.shopId);
|
||||
// platformPermission
|
||||
out.platformPermission = JSON.stringify(d.platformPermission||{}).slice(0, 500);
|
||||
// shopDataMap
|
||||
const sdm = d.shopDataMap||{};
|
||||
const k2 = Object.keys(sdm)[0];
|
||||
out.shopDataMapSample = k2? (k2+' => '+JSON.stringify(sdm[k2]).slice(0,300)) : '(空)';
|
||||
// 按 platform 归类
|
||||
const byPlat = {};
|
||||
for (const [k,v] of Object.entries(sm)) {
|
||||
const p = (v&&(v.platform||v.platformName||v.type))||'?';
|
||||
(byPlat[p]=byPlat[p]||[]).push((v&&(v.name||v.shopName))||k);
|
||||
}
|
||||
out.byPlatform = byPlat;
|
||||
return JSON.stringify(out);
|
||||
})()`, true);
|
||||
try{
|
||||
const d = JSON.parse(String(r));
|
||||
console.log(' smtShopId:', d.smtShopId, '| shopId:', d.shopId);
|
||||
console.log();
|
||||
console.log(' shopMap 条目结构:'); console.log(' ', SAN(d.shopMapSample).slice(0,380));
|
||||
console.log(' shopDataMap 样例:'); console.log(' ', SAN(d.shopDataMapSample).slice(0,300));
|
||||
console.log(' shopSmtTypeMap:'); console.log(' ', SAN(d.smtTypeMap).slice(0,380));
|
||||
console.log(' platformPermission:'); console.log(' ', SAN(d.platformPermission).slice(0,480));
|
||||
console.log();
|
||||
console.log(' ── 按平台归类 ──');
|
||||
for (const [p, arr] of Object.entries(d.byPlatform||{})) console.log(' ' + p + ' (' + arr.length + '): ' + arr.slice(0,8).join(', '));
|
||||
}catch(e){ console.log('err', e.message, SAN(String(r)).slice(0,700)); }
|
||||
c.close();
|
||||
@@ -0,0 +1,13 @@
|
||||
[
|
||||
"⑧Shein-易世通达-文具",
|
||||
"⑦shein-易捷天宇-家居",
|
||||
"⑩Shein-南京九个网-美妆",
|
||||
"⑨Shein-南京亿千-运动",
|
||||
"③shein-易捷天宇-美妆",
|
||||
"⑤Shein-惠州九衢-内睡(袜子)",
|
||||
"④Shein-武汉玖璨-家居",
|
||||
"⑥Shein-南京亿千-文具",
|
||||
"①Shein-武汉九个网-箱包",
|
||||
"②Shein-易世通达-箱包",
|
||||
"⑪-南京九个网-家居"
|
||||
]
|
||||
@@ -0,0 +1,17 @@
|
||||
[
|
||||
"①Alimingpro",
|
||||
"②ALuckycao",
|
||||
"③Bagbelle",
|
||||
"④Caoup",
|
||||
"⑤Bookinq",
|
||||
"⑥Wxzgz",
|
||||
"⑦Zdcjl",
|
||||
"⑧Ewhe",
|
||||
"⑨wowimartq",
|
||||
"⑩JoyJumbe",
|
||||
"⑪ Chugupi",
|
||||
"⑫Qapple",
|
||||
"⑬Wbalana",
|
||||
"⑮Tapeach",
|
||||
"⑭HoHaven"
|
||||
]
|
||||
@@ -0,0 +1,12 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
const o = await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/主规格/.test(l.innerText||'');});
|
||||
if(!it)return'nf'; const box=it.querySelector('.sku-info-box')||it;
|
||||
const first=[...box.querySelectorAll('.sku-option')].filter(e=>e.offsetParent!==null)[0];
|
||||
if(!first)return'no-opt';
|
||||
return JSON.stringify({outer:first.outerHTML.slice(0,600),
|
||||
parentCls:String(first.parentElement.className||'').slice(0,60),
|
||||
sibCount:first.parentElement.children.length});})()`);
|
||||
console.log(String(o).slice(0,900));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,31 @@
|
||||
import { attach, SAN } from '/tmp/cdp3.mjs';
|
||||
import fs from 'fs';
|
||||
const all=JSON.parse(fs.readFileSync('/tmp/all48.json','utf8'));
|
||||
const wm=JSON.parse(fs.readFileSync('/tmp/wm_verdicts.json','utf8'));
|
||||
const clean=JSON.parse(fs.readFileSync('/tmp/wm_clean.json','utf8'));
|
||||
const SHORT=['1027332215847','601964534137','750271307455'];
|
||||
const c=await attach('/web/smt/smtProductList/draft')||await attach('dianxiaomi.com');
|
||||
await c.send('Runtime.enable');
|
||||
for(const oid of SHORT){
|
||||
const info=all[oid];
|
||||
const raw=await c.evalJS(`(async()=>{
|
||||
const rr=await fetch('/api/ozonProduct/add.json?id=${info.pid}&_t='+Date.now(),{headers:{'X-Requested-With':'XMLHttpRequest'}});
|
||||
const tx=await rr.text(); if(!tx.startsWith('{'))return'{}';
|
||||
const p=JSON.parse(tx).data.product;
|
||||
const s=new Set(); if(p.mainImage) s.add(p.mainImage);
|
||||
(p.extraImages||'').split(';').filter(Boolean).forEach(u=>s.add(u));
|
||||
return JSON.stringify({name:(p.name||'').slice(0,40), main:p.mainImage, urls:[...s]});
|
||||
})()`,true);
|
||||
const d=JSON.parse(String(raw));
|
||||
console.log('\n ════ '+oid+' ════');
|
||||
console.log(' '+d.name);
|
||||
console.log(' 干净图: '+(clean[oid]||[]).length+' 张');
|
||||
console.log(' ── 全部候选图的判定 ──');
|
||||
(d.urls||[]).slice(0,18).forEach((u,i)=>{
|
||||
const v=wm[u];
|
||||
const tag = !v ? '?' : (v.err? '✗'+v.err : (v.wm||v.contact? '⚠水印':'✅干净'));
|
||||
const txt = v && (v.text||v.reason) ? (' | '+String(v.text||v.reason).slice(0,50)) : '';
|
||||
console.log(` [${i}] ${tag.padEnd(8)} ${u.split('/').pop().split('_')[0].slice(0,26)}${txt}`);
|
||||
});
|
||||
}
|
||||
c.close();
|
||||
@@ -0,0 +1,24 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
const pick = await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/主规格/.test(l.innerText||'');});
|
||||
if(!it)return'nf'; const box=it.querySelector('.sku-info-box')||it;
|
||||
const opts=[...box.querySelectorAll('.sku-option')].filter(e=>e.offsetParent!==null);
|
||||
const hit=opts.find(e=>/Multicolor|Black\\(/.test(e.innerText||''))||opts[0];
|
||||
if(!hit)return'no-opt';
|
||||
for(const ev of ['mousedown','mouseup','click']) hit.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window}));
|
||||
return 'picked:'+(hit.innerText||'').trim();})()`);
|
||||
console.log('选色:', pick);
|
||||
await wait(6000);
|
||||
const o = await c.evalJS(`(()=>{
|
||||
const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const tbls=[...document.querySelectorAll('table')].filter(t=>t.offsetParent!==null).map(t=>({
|
||||
th:[...t.querySelectorAll('th')].map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim()).slice(0,15),
|
||||
rows:[...t.querySelectorAll('tbody tr')].filter(x=>x.querySelectorAll('input').length).length}));
|
||||
const d=JSON.parse(JSON.stringify(p._s.get('sheinSkuDataStore').$state));
|
||||
const a=JSON.parse(JSON.stringify(p._s.get('sheinSkuAttrStore').$state));
|
||||
return JSON.stringify({tbls, n:(d.formState.skuDataList||[]).length, row0:(d.formState.skuDataList||[])[0],
|
||||
chosen:(a.formState.skuAttrs||[]).map(x=>({name:x.name, vals:(x.attributeValues||[]).map(v=>v.attribute_value||v) }))},null,1);})()`);
|
||||
console.log(String(o).slice(0,1900));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,53 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
const reqs=[];
|
||||
c.on(m=>{ if(m.method==='Network.requestWillBeSent'){const r=m.params.request;
|
||||
if(/shein/i.test(r.url)&&/\.json/.test(r.url)&&r.method==='POST') reqs.push(r.url.replace('https://www.dianxiaomi.com','')); }});
|
||||
await c.send('Network.enable').catch(()=>{});
|
||||
// 重填 SKU 行
|
||||
const r = await c.evalJS(`(()=>{const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const d=p._s.get('sheinSkuDataStore').$state.formState;
|
||||
const rows=d.skuDataList||[]; let n=0;
|
||||
rows.forEach((x,i)=>{ x.skcSupplierCode='SHEIN-'+String(i+1).padStart(3,'0'); x.skcRetailPrice='12.90';
|
||||
x.supplyPrice='8.50'; x.stockVariety='999'; x.weight='100'; x.length='200'; x.width='150'; x.height='30'; n++; });
|
||||
return 'rows:'+n;})()`);
|
||||
console.log('重填 SKU:', r);
|
||||
await wait(2500);
|
||||
// 重填尺码表(走弹窗)
|
||||
await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/尺码表/.test(l.innerText||'');});
|
||||
if(!it)return 0; const el=it.querySelector('.link')||it.querySelector('a,span'); if(!el)return 0;
|
||||
el.scrollIntoView({block:'center'});
|
||||
for(const ev of ['mousedown','mouseup','click']) el.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return 1;})()`);
|
||||
await wait(5000);
|
||||
const f = await c.evalJS(`(()=>{const m=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!m)return'no-modal'; const ins=[...m.querySelectorAll('input')].filter(i=>i.offsetParent!==null&&i.placeholder==='请输入');
|
||||
const vals=['10','18','3','2','18','5']; let n=0;
|
||||
ins.forEach((el,i)=>{ if(i>=vals.length)return; el.focus();
|
||||
Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,'value').set.call(el,vals[i]);
|
||||
el.dispatchEvent(new Event('input',{bubbles:true})); el.dispatchEvent(new Event('change',{bubbles:true})); el.dispatchEvent(new Event('blur',{bubbles:true})); n++; });
|
||||
return 'filled:'+n;})()`);
|
||||
console.log('尺码表:', f);
|
||||
await wait(1200);
|
||||
await c.evalJS(`(()=>{const m=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(m){const b=[...m.querySelectorAll('button')].find(x=>/^\\s*确定\\s*$/.test(x.innerText||'')); if(b) for(const ev of ['mousedown','mouseup','click']) b.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window}));} return 1;})()`);
|
||||
await wait(4000);
|
||||
// 重填图片(可能也被清了)
|
||||
await c.evalJS(`(()=>{const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const im=p._s.get('sheinImgStore').$state.formState;
|
||||
const cur=im.mainImgData.multipleSpuImgs;
|
||||
const urls=${JSON.stringify(['https://cbu01.alicdn.com/img/ibank/O1CN01IHtNAHKMzNC1chua_!!2222444614399-0-cib.jpg','https://cbu01.alicdn.com/img/ibank/O1CN01UGEWafTzqTH1chua_!!2222444614399-0-cib.jpg','https://cbu01.alicdn.com/img/ibank/O1CN01d0hA4N72jzD1chua_!!2222444614399-0-cib.jpg','https://cbu01.alicdn.com/img/ibank/O1CN01edgGxIlmdtJ1chua_!!2222444614399-0-cib.jpg'])};
|
||||
if(!Array.isArray(cur)||cur.length<4){ im.mainImgData.multipleSpuImgs=urls.map((u,i)=>({url:u,imgUrl:u,name:'img'+(i+1)+'.jpg',width:800,height:800})); }
|
||||
return 'imgs:'+(Array.isArray(im.mainImgData.multipleSpuImgs)?im.mainImgData.multipleSpuImgs.length:'?');})()`);
|
||||
await wait(2500);
|
||||
// 保存
|
||||
await c.evalJS(`window.scrollTo(0,0)`); await wait(600);
|
||||
await c.evalJS(`(()=>{const x=[...document.querySelectorAll('button')].filter(e=>e.offsetParent!==null).find(e=>/^\\s*保存\\s*$/.test((e.innerText||'').trim()));
|
||||
if(x) for(const ev of ['mousedown','mouseup','click']) x.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return 1;})()`);
|
||||
await wait(12000);
|
||||
console.log('捕获:', String(await c.evalJS(`JSON.stringify(window.__cap||[])`)).slice(0,300));
|
||||
console.log('POST:', JSON.stringify([...new Set(reqs)].slice(0,3)));
|
||||
const t = await c.evalJS(`JSON.stringify([...document.querySelectorAll('.ant-message-notice,.ant-notification-notice,.ant-modal')].filter(e=>e.offsetParent!==null).map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim().slice(0,130)).filter(Boolean).slice(0,3))`);
|
||||
console.log('提示:', String(t).slice(0,400));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,35 @@
|
||||
import { newTarget, CDP } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const SHOP = process.argv[2];
|
||||
const tl = await (await fetch('http://127.0.0.1:9223/json/list')).json();
|
||||
for (const t of tl.filter(x=>x.type==='page'&&/shein/i.test(x.url))) await fetch(`http://127.0.0.1:9223/json/close/${t.id}`).catch(()=>{});
|
||||
await wait(1000);
|
||||
const t = await newTarget('about:blank');
|
||||
const c = await CDP.connect(t.webSocketDebuggerUrl);
|
||||
await c.send('Page.enable'); await c.send('Runtime.enable');
|
||||
await c.send('Page.navigate',{url:'https://www.dianxiaomi.com/web/sheinProduct/add'});
|
||||
await wait(21000);
|
||||
const pos = JSON.parse(String(await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/店铺/.test(l.innerText||'');});
|
||||
const s=(it||document).querySelector('.ant-select-selector'); s.scrollIntoView({block:'center'});
|
||||
const r=s.getBoundingClientRect(); return JSON.stringify([Math.round(r.x+r.width/2),Math.round(r.y+r.height/2)]);})()`)));
|
||||
for (const type of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type,x:pos[0],y:pos[1],button:'left',clickCount:1});
|
||||
await wait(2500);
|
||||
await c.evalJS(`(()=>{const dd=[...document.querySelectorAll('.ant-select-dropdown')].filter(e=>e.offsetParent!==null).pop();
|
||||
const hit=[...dd.querySelectorAll('.ant-select-item-option')].find(o=>(o.innerText||'').trim()===${JSON.stringify(SHOP)});
|
||||
if(hit) for(const ev of ['mousedown','mouseup','click']) hit.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return 1;})()`);
|
||||
await wait(8000);
|
||||
// 开分类下拉
|
||||
const cp = JSON.parse(String(await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/产品分类/.test(l.innerText||'');});
|
||||
const s=it.querySelector('.ant-select-selector'); s.scrollIntoView({block:'center'});
|
||||
const r=s.getBoundingClientRect(); return JSON.stringify([Math.round(r.x+r.width/2),Math.round(r.y+r.height/2)]);})()`)));
|
||||
for (const type of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type,x:cp[0],y:cp[1],button:'left',clickCount:1});
|
||||
await wait(3500);
|
||||
const o = await c.evalJS(`(()=>{const dd=[...document.querySelectorAll('.ant-select-dropdown')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!dd)return'no-dd';
|
||||
const opts=[...dd.querySelectorAll('.ant-select-item-option')].map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim());
|
||||
return JSON.stringify({n:opts.length, opts:opts.slice(0,26)});})()`);
|
||||
console.log('════', SHOP);
|
||||
console.log(String(o).slice(0,1100));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,21 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
const pos = JSON.parse(String(await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/尺码表/.test(l.innerText||'');});
|
||||
if(!it)return'[]'; const el=it.querySelector('.link')||it.querySelector('a,span');
|
||||
if(!el)return'[]'; el.scrollIntoView({block:'center'}); const r=el.getBoundingClientRect();
|
||||
return JSON.stringify([Math.round(r.x+r.width/2),Math.round(r.y+r.height/2)]);})()`)));
|
||||
console.log('编辑尺码表坐标:', JSON.stringify(pos));
|
||||
if(pos.length){ for(const type of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type,x:pos[0],y:pos[1],button:'left',clickCount:1}); }
|
||||
await wait(6000);
|
||||
const o = await c.evalJS(`(()=>{
|
||||
const ms=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null).map(m=>({t:(m.querySelector('.ant-modal-title')||{}).innerText||'',
|
||||
inputs:[...m.querySelectorAll('input')].map(i=>i.placeholder||i.type).slice(0,8),
|
||||
btns:[...m.querySelectorAll('button')].map(b=>(b.innerText||'').trim()).slice(0,8),
|
||||
txt:(m.innerText||'').replace(/\\s+/g,' ').slice(0,320)}));
|
||||
const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
let sz=null; try{ sz=JSON.stringify(p._s.get('sheinSkuAttrStore').$state.formState.sizeTableInfo).slice(0,200);}catch(e){}
|
||||
return JSON.stringify({modals:ms, sizeTableInfo:sz},null,1);})()`);
|
||||
console.log(String(o).slice(0,1400));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,18 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
// 打开尺码表弹窗
|
||||
const pos = JSON.parse(String(await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/尺码表/.test(l.innerText||'');});
|
||||
if(!it)return'[]'; const el=it.querySelector('.link')||it.querySelector('a,span'); if(!el)return'[]';
|
||||
el.scrollIntoView({block:'center'}); const r=el.getBoundingClientRect();
|
||||
return JSON.stringify([Math.round(r.x+r.width/2),Math.round(r.y+r.height/2)]);})()`)));
|
||||
if(pos.length){ for(const t of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type:t,x:pos[0],y:pos[1],button:'left',clickCount:1}); }
|
||||
await wait(6000);
|
||||
const o = await c.evalJS(`(()=>{const m=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!m)return'no-modal';
|
||||
const rows=[...m.querySelectorAll('tr')].slice(0,10).map(tr=>[...tr.querySelectorAll('td,th')].map(td=>{
|
||||
const i=td.querySelector('input'); return i?('IN:'+(i.placeholder||i.value||'')):(td.innerText||'').replace(/\\s+/g,' ').trim().slice(0,18);}));
|
||||
return JSON.stringify({title:(m.querySelector('.ant-modal-title')||{}).innerText||'', rows, btns:[...m.querySelectorAll('button')].map(b=>(b.innerText||'').trim()).slice(0,10)},null,1);})()`);
|
||||
console.log(String(o).slice(0,1500));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,47 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
const reqs=[];
|
||||
c.on(m=>{ if(m.method==='Network.requestWillBeSent'){const r=m.params.request;
|
||||
if(/shein/i.test(r.url)&&/\.json/.test(r.url)&&r.method==='POST') reqs.push(r.url.replace('https://www.dianxiaomi.com','')); }});
|
||||
await c.send('Network.enable').catch(()=>{});
|
||||
// 填 6 格
|
||||
const f = await c.evalJS(`(()=>{const m=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!m)return'no-modal'; const ins=[...m.querySelectorAll('input')].filter(i=>i.offsetParent!==null);
|
||||
const vals=['10','18','3','2','18','5']; let n=0;
|
||||
ins.forEach((el,i)=>{ if(i>=vals.length)return;
|
||||
el.focus(); Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,'value').set.call(el, vals[i]);
|
||||
el.dispatchEvent(new Event('input',{bubbles:true})); el.dispatchEvent(new Event('change',{bubbles:true}));
|
||||
el.dispatchEvent(new Event('blur',{bubbles:true})); n++; });
|
||||
return 'filled:'+n+'/'+ins.length;})()`);
|
||||
console.log('填尺码表:', f);
|
||||
await wait(1500);
|
||||
// 确定
|
||||
await c.evalJS(`(()=>{const m=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!m)return 0; const b=[...m.querySelectorAll('button')].find(x=>/^\\s*确定\\s*$/.test(x.innerText||''));
|
||||
if(b) for(const ev of ['mousedown','mouseup','click']) b.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return 1;})()`);
|
||||
await wait(5000);
|
||||
const st = await c.evalJS(`(()=>{const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const a=p._s.get('sheinSkuAttrStore').$state.formState;
|
||||
const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/尺码表/.test(l.innerText||'');});
|
||||
return JSON.stringify({sizeTableInfo:String(JSON.stringify(a.sizeTableInfo)).slice(0,200), ui:(it?it.innerText:'').replace(/\\s+/g,' ').slice(0,60)});})()`);
|
||||
console.log('尺码表状态:', String(st).slice(0,300));
|
||||
// 保存
|
||||
await c.evalJS(`window.scrollTo(0,0)`); await wait(600);
|
||||
await c.evalJS(`(()=>{const xs=[...document.querySelectorAll('button')].filter(e=>e.offsetParent!==null);
|
||||
const x=xs.find(e=>/^\\s*保存\\s*$/.test((e.innerText||'').trim())); if(!x)return 0;
|
||||
for(const ev of ['mousedown','mouseup','click']) x.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return 1;})()`);
|
||||
await wait(14000);
|
||||
await c.evalJS(`(()=>{const ms=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null);
|
||||
for(const m of ms){const b=[...m.querySelectorAll('button')].find(x=>/确定|确认|继续编辑/.test(x.innerText||'')); if(b)b.click();} return 1;})()`);
|
||||
await wait(4000);
|
||||
console.log('POST:', JSON.stringify([...new Set(reqs)].slice(0,4)));
|
||||
const red = await c.evalJS(`(()=>{const red=[]; document.querySelectorAll('*').forEach(el=>{ if(el.offsetParent===null||el.children.length)return;
|
||||
const t=(el.innerText||'').trim(); if(!t||t.length>60)return;
|
||||
const s=getComputedStyle(el); const m=(s.color||'').match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/); if(!m)return;
|
||||
if(+m[1]>160&&+m[2]<140&&+m[3]<140) red.push(t); });
|
||||
const toasts=[...document.querySelectorAll('.ant-message-notice,.ant-notification-notice,.ant-modal')].map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim()).filter(Boolean);
|
||||
return JSON.stringify({red:[...new Set(red)].slice(0,10), toasts:[...new Set(toasts)].slice(0,3)});})()`);
|
||||
console.log('红字/提示:', String(red).slice(0,600));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,38 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
const reqs=[];
|
||||
c.on(m=>{ if(m.method==='Network.requestWillBeSent'){const r=m.params.request;
|
||||
if(/shein/i.test(r.url)&&/\.json/.test(r.url)&&r.method==='POST') reqs.push(r.url.replace('https://www.dianxiaomi.com','')); }});
|
||||
await c.send('Network.enable').catch(()=>{});
|
||||
const f = await c.evalJS(`(()=>{const m=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!m)return'no-modal';
|
||||
const ins=[...m.querySelectorAll('input')].filter(i=>i.offsetParent!==null&&i.placeholder==='请输入');
|
||||
const vals=['10','18','3','2','18','5']; let n=0;
|
||||
ins.forEach((el,i)=>{ if(i>=vals.length)return;
|
||||
el.focus(); Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,'value').set.call(el, vals[i]);
|
||||
el.dispatchEvent(new Event('input',{bubbles:true})); el.dispatchEvent(new Event('change',{bubbles:true}));
|
||||
el.dispatchEvent(new Event('blur',{bubbles:true})); n++; });
|
||||
return 'filled:'+n+'/'+ins.length+' vals='+ins.map(i=>i.value).join(',');})()`);
|
||||
console.log('填:', f);
|
||||
await wait(1500);
|
||||
await c.evalJS(`(()=>{const m=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!m)return 0; const b=[...m.querySelectorAll('button')].find(x=>/^\\s*确定\\s*$/.test(x.innerText||''));
|
||||
if(b) for(const ev of ['mousedown','mouseup','click']) b.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return 1;})()`);
|
||||
await wait(5000);
|
||||
const st = await c.evalJS(`(()=>{const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const a=p._s.get('sheinSkuAttrStore').$state.formState;
|
||||
const openM=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null&&/编辑尺码表/.test(e.innerText||'')).length;
|
||||
return JSON.stringify({sizeTableInfo:String(JSON.stringify(a.sizeTableInfo)).slice(0,240), modalOpen:openM});})()`);
|
||||
console.log('尺码表:', String(st).slice(0,340));
|
||||
await c.evalJS(`window.scrollTo(0,0)`); await wait(600);
|
||||
await c.evalJS(`(()=>{const x=[...document.querySelectorAll('button')].filter(e=>e.offsetParent!==null).find(e=>/^\\s*保存\\s*$/.test((e.innerText||'').trim()));
|
||||
if(!x)return 0; for(const ev of ['mousedown','mouseup','click']) x.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return 1;})()`);
|
||||
await wait(14000);
|
||||
await c.evalJS(`(()=>{const ms=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null);
|
||||
for(const m of ms){const b=[...m.querySelectorAll('button')].find(x=>/确定|确认|继续编辑/.test(x.innerText||'')); if(b)b.click();} return 1;})()`);
|
||||
await wait(4000);
|
||||
console.log('POST:', JSON.stringify([...new Set(reqs)].slice(0,4)));
|
||||
const t = await c.evalJS(`(()=>[...document.querySelectorAll('.ant-message-notice,.ant-notification-notice,.ant-modal')].filter(e=>e.offsetParent!==null).map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim().slice(0,120)).filter(Boolean).slice(0,3))()`);
|
||||
console.log('提示:', String(t).slice(0,400));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,15 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
const o = await c.evalJS(`(()=>{
|
||||
const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/主规格/.test(l.innerText||'');});
|
||||
if(!it)return'nf';
|
||||
const box=it.querySelector('.sku-info-box')||it;
|
||||
// 列出所有叶子的 tag/class/文本
|
||||
const leaves=[...box.querySelectorAll('*')].filter(e=>e.offsetParent!==null&&!e.children.length&&(e.innerText||'').trim())
|
||||
.slice(0,14).map(e=>({tag:e.tagName, cls:String(e.className||'').slice(0,55), t:(e.innerText||'').trim().slice(0,18)}));
|
||||
const clickable=[...box.querySelectorAll('button,.ant-btn,.ant-tag,.ant-checkbox-wrapper,[class*=tag],[class*=item],[class*=option]')]
|
||||
.filter(e=>e.offsetParent!==null).slice(0,12).map(e=>({tag:e.tagName, cls:String(e.className||'').slice(0,50), t:(e.innerText||'').trim().slice(0,16)}));
|
||||
return JSON.stringify({leafCount:box.querySelectorAll('*').length, leaves, clickable},null,1);})()`);
|
||||
console.log(String(o).slice(0,2000));
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,30 @@
|
||||
import { attach } from '/tmp/cdp3.mjs';
|
||||
const wait = ms => new Promise(z => setTimeout(z, ms));
|
||||
const c = await attach('/web/sheinProduct/add') || await attach('dianxiaomi.com');
|
||||
// 1. 主规格控件
|
||||
const o1 = await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/主规格/.test(l.innerText||'');});
|
||||
if(!it)return'nf'; return JSON.stringify({txt:(it.innerText||'').replace(/\\s+/g,' ').slice(0,160), html:it.innerHTML.slice(0,500)});})()`);
|
||||
console.log('主规格:', String(o1).slice(0,700));
|
||||
// 2. 尺码表控件
|
||||
const o2 = await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/尺码表/.test(l.innerText||'');});
|
||||
if(!it)return'nf'; return JSON.stringify({txt:(it.innerText||'').replace(/\\s+/g,' ').slice(0,160), html:it.innerHTML.slice(0,400)});})()`);
|
||||
console.log('尺码表:', String(o2).slice(0,600));
|
||||
// 3. 图片区
|
||||
const o3 = await c.evalJS(`(()=>{const it=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(x=>{const l=x.querySelector('label'); return l&&/图片/.test(l.innerText||'');});
|
||||
if(!it)return'nf'; return JSON.stringify({lab:(it.querySelector('label')||{}).innerText||'', txt:(it.innerText||'').replace(/\\s+/g,' ').slice(0,200)});})()`);
|
||||
console.log('图片区:', String(o3).slice(0,500));
|
||||
// 4. 主规格可选值(第一个属性)
|
||||
const o4 = await c.evalJS(`(()=>{const p=document.querySelector('#app').__vue_app__.config.globalProperties.$pinia;
|
||||
const a=JSON.parse(JSON.stringify(p._s.get('sheinSkuAttrStore').$state));
|
||||
const at=(a.formState.skuAttrs||[])[0]||{};
|
||||
return JSON.stringify({attrName:at.name, attrId:at.attributeId, optCount:(at._options||[]).length,
|
||||
opt0:(at._options||[])[0], chosen:at.attributeValues||at.checked||null});})()`);
|
||||
console.log('主规格属性:', String(o4).slice(0,600));
|
||||
// 5. 是否有必填标记的项
|
||||
const o5 = await c.evalJS(`(()=>[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null&&e.querySelector('.ant-form-item-required'))
|
||||
.map(x=>{const l=x.querySelector('label'); return l?(l.innerText||'').replace(/\\s+/g,' ').trim():'';}).filter(Boolean).slice(0,15))()`);
|
||||
console.log('必填项:', String(o5).slice(0,400));
|
||||
process.exit(0);
|
||||
Reference in new issue
Block a user