- TikTok/Shopee/速卖通/Walmart 各 46-47 条已在待发布 - Ozon 47 条已建、改价 40/47 - SHEIN 配方跑通第一条;Temu 差「预览图」一步 - 核心产出:MYJ.message.error 钩子诊断法(解开了三个平台的保存静默拦截) - 含下一轮提示词 NEXT-ROUND-PROMPT.md
95 lines
6.3 KiB
JavaScript
95 lines
6.3 KiB
JavaScript
import { newTarget, CDP, SAN } from '/tmp/cdp3.mjs';
|
|
|
|
/* 就地改 Shopee 产品类目:node spfixcat.mjs <productId> <title> <kw1,kw2,...> */
|
|
const PID = process.argv[2];
|
|
const TITLE = process.argv[3] || '';
|
|
const KWS = (process.argv[4] || '').split(',').filter(Boolean);
|
|
if (!PID || !KWS.length) { console.log('用法: node spfixcat.mjs <productId> <title> <kw1,kw2>'); process.exit(1); }
|
|
|
|
const wait = ms => new Promise(z => setTimeout(z, ms));
|
|
const log = (...a) => console.log(' ', ...a);
|
|
const IS_KID = /baby|kid|infant|toddler|children|newborn/i.test(TITLE);
|
|
const IS_AUTO = /car|auto|moto|vehicle|truck|bicycle|bike/i.test(TITLE);
|
|
|
|
const tl = await (await fetch('http://127.0.0.1:9223/json/list')).json();
|
|
for (const t of tl.filter(x => x.type === 'page' && /shopee/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/shopeeGlobal/edit?id=${PID}` });
|
|
await wait(26000);
|
|
for (let i = 0; i < 8; i++) {
|
|
const x = await c.evalJS(`(()=>{const ms=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null);
|
|
if(!ms.length)return'n'; ms.forEach(m=>{const cb=m.querySelector('.ant-modal-close'); if(cb&&cb.offsetParent!==null)cb.click();}); return 'c';})()`);
|
|
if (x === 'n') break; await wait(1000);
|
|
}
|
|
await wait(2000);
|
|
log('URL:', await c.evalJS('location.href'));
|
|
log('店铺:', 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&&it.querySelector('.ant-select-selection-item'); return s?s.innerText.trim():'';})()`));
|
|
|
|
async function pickCategory(kw) {
|
|
await c.evalJS(`(()=>{document.querySelectorAll('.ant-select-dropdown').forEach(d=>{if(d.offsetParent!==null)d.style.display='none';}); document.body.click(); return 1;})()`);
|
|
await wait(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 b=[...it.querySelectorAll('button,a,span')].filter(e=>e.offsetParent!==null&&/^\\s*选择分类\\s*$/.test((e.innerText||'').trim()));
|
|
if(!b.length)return'[]'; const el=b[b.length-1]; 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) return 'no-btn';
|
|
for (const type of ['mousePressed', 'mouseReleased']) await c.send('Input.dispatchMouseEvent', { type, x: pos[0], y: pos[1], button: 'left', clickCount: 1 });
|
|
await wait(3500);
|
|
const r = await c.evalJS(`(()=>{const m=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null).pop();
|
|
if(!m)return'no-modal'; const inp=m.querySelector('input[placeholder="搜索分类名称"]'); if(!inp)return'no-input';
|
|
inp.focus(); Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,'value').set.call(inp,${JSON.stringify(kw)});
|
|
inp.dispatchEvent(new Event('input',{bubbles:true})); inp.dispatchEvent(new Event('change',{bubbles:true}));
|
|
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 'searched';})()`);
|
|
if (r !== 'searched') return r;
|
|
await wait(4000);
|
|
const pick = await c.evalJS(`(()=>{const m=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null).pop();
|
|
if(!m)return'no-modal'; const its=[...m.querySelectorAll('.search-result-item')]; if(!its.length)return'no-result';
|
|
const BAD=/二手|Second-?hand|Used|Pre-?owned|Refurb|Sexual|Sex Toy|情趣|Adult Toy|Dewasa/i;
|
|
const KID=/Bayi|Baby|Kids|Kid|Infant|Toddler|Children|Kanak/i;
|
|
const AUTO=/Automobile|Automotive|Motosikal|汽车|车贴|Emblem/i;
|
|
const ISK=${IS_KID}, ISA=${IS_AUTO};
|
|
const KW=${JSON.stringify(kw)}.toLowerCase();
|
|
const texts=its.map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim());
|
|
const ok=t=>!BAD.test(t)&&(ISK||!KID.test(t))&&(ISA||!AUTO.test(t));
|
|
const lastSeg=t=>{const a=t.split('/'); return (a[a.length-1]||'').replace(/\\(.*?\\)/g,'').trim().toLowerCase();};
|
|
let idx=texts.findIndex(t=>ok(t)&&lastSeg(t).includes(KW));
|
|
if(idx<0) idx=texts.findIndex(t=>ok(t)&&t.toLowerCase().includes(KW));
|
|
if(idx<0) idx=texts.findIndex(t=>ok(t));
|
|
if(idx<0) idx=texts.findIndex(t=>!BAD.test(t));
|
|
if(idx<0) idx=0;
|
|
const hit=its[idx];
|
|
for(const ev of ['mousedown','mouseup','click']) hit.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window}));
|
|
return 'picked['+idx+'/'+texts.length+']:'+texts[idx];})()`);
|
|
await wait(4500);
|
|
return pick;
|
|
}
|
|
|
|
let done = null;
|
|
for (const kw of KWS) {
|
|
const r = String(await pickCategory(kw));
|
|
log(' ', kw, '→', SAN(r).slice(0, 130));
|
|
if (!/no-result|no-input|no-modal|no-btn/.test(r)) { done = r; break; }
|
|
await c.evalJS(`(()=>{const m=[...document.querySelectorAll('.ant-modal')].filter(e=>e.offsetParent!==null).pop();
|
|
if(m){const x=m.querySelector('.ant-modal-close'); if(x&&x.offsetParent!==null)x.click();} return 1;})()`);
|
|
await wait(1500);
|
|
}
|
|
if (!done) { log('❌ 全部关键词无结果'); process.exit(2); }
|
|
|
|
const sv = await c.evalJS(`(()=>{const b=[...document.querySelectorAll('button,a,span')].filter(e=>e.offsetParent!==null&&/^\\s*保存\\s*$/.test(e.innerText||''));
|
|
if(!b.length)return'nf'; for(const ev of ['mousedown','mouseup','click']) b[b.length-1].dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return 'clicked';})()`);
|
|
log('保存:', sv);
|
|
await wait(9000);
|
|
const msg = await c.evalJS(`(()=>{const ms=[...document.querySelectorAll('.ant-message-notice,.ant-notification-notice')].filter(e=>e.offsetParent!==null)
|
|
.map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim().slice(0,140)).filter(Boolean); return JSON.stringify(ms.slice(0,3));})()`);
|
|
log('结果:', SAN(String(msg)).slice(0, 260));
|
|
process.exit(done ? 0 : 2);
|