From e5545331ce623a8c34d9d8908472b200f4471761 Mon Sep 17 00:00:00 2001 From: admin9webs Date: Mon, 21 Sep 2026 10:13:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A6=99=E6=89=8B=EF=BC=9A=E8=AF=81=E4=BC=AA?= =?UTF-8?q?=E3=80=8C=E5=85=B3=E8=81=94=E8=B4=A7=E6=BA=90=E7=AD=9B=E9=80=89?= =?UTF-8?q?=E8=97=8F=E6=95=B0=E6=8D=AE=E3=80=8D=EF=BC=88=E5=BD=93=E5=89=8D?= =?UTF-8?q?=3D=E5=85=A8=E9=83=A8=E5=85=B3=E8=81=94=E8=B4=A7=E6=BA=90?= =?UTF-8?q?=EF=BC=89=EF=BC=9B=E5=AF=BC=E5=85=A5=E8=A1=8C=E6=97=A0=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E5=8A=A8=E4=BD=9C=EF=BC=8C=E8=A7=A6=E5=8F=91=E7=82=B9?= =?UTF-8?q?=E5=9C=A8=E9=87=87=E9=9B=86=E7=AE=B1=E7=9A=84=E3=80=8C=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E4=BA=A7=E5=93=81=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 妙手建品/RECIPE.md | 17 +++++++++++++++++ 妙手建品/ms_filter.mjs | 40 ++++++++++++++++++++++++++++++++++++++++ 妙手建品/ms_more.mjs | 27 +++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 妙手建品/ms_filter.mjs create mode 100644 妙手建品/ms_more.mjs diff --git a/妙手建品/RECIPE.md b/妙手建品/RECIPE.md index 80f7141..74a36bf 100644 --- a/妙手建品/RECIPE.md +++ b/妙手建品/RECIPE.md @@ -202,3 +202,20 @@ await c.send('DOM.setFileInputFiles', { files: ['/path/ms_import.csv'], nodeId } ⚠️ 结论:**导入≠已采集**。`解析成功` 只代表表格被接受,真正抓取需要触发(或等到队列跑)。 判定标准只有一个:**公用采集箱里出现 47 条**。 + +## 第 4 轮:假设 1 被证伪;触发点在采集箱的「导入产品」 + +1. **`关联货源` 筛选不是原因**:控件是 `div.jx-select.pro-select`, + 当前值就是 **「全部关联货源」** —— 没有任何筛选把数据藏住。 + 所以**这 47 条确实还没被采集进箱**,不是被筛掉了。 +2. **导入列表的成功行没有触发动作**:`ms2` 行只有 `查看导入产品 / 删除文件` 两个操作 + (失败行多一个 `查看失败原因`),**没有 `更多` 菜单**。 + 而 `查看导入产品` 实测点不动(DOM 与真实鼠标都试过,无弹窗/无新标签/URL 不变)。 +3. **因此触发点最可能在「公用采集箱」页里的 `导入产品` 按钮**: + 该页按钮清单是 `任务记录 / 搜索 / 重置 / 更多筛选 / 认领到 / 平台认领配置 / 批量编辑 / + 分组 / 删除 / 更多 / 创建产品 / **导入产品** / 列表设置 / 全选` —— + 「导入产品」很可能就是把已解析的导入文件拉进采集箱(并启动采集)的入口。 + +### 下一步(明确到一次点击) +进 `/common_collect_box/items` → 点 **`导入产品`** → 看它是否列出 `ms2`(或那 47 条)→ +选择并确认 → 回到列表看是否出现 47 条 → 然后才是 `认领到` → 发布权限验证。 diff --git a/妙手建品/ms_filter.mjs b/妙手建品/ms_filter.mjs new file mode 100644 index 0000000..184e527 --- /dev/null +++ b/妙手建品/ms_filter.mjs @@ -0,0 +1,40 @@ +import { listPages, wait } from '/home/admin9webs/shein建品/sh_lib.mjs'; +import { CDP, SAN as S } from '/tmp/cdp3.mjs'; +const t = (await listPages()).find(x=>/91miaoshou/i.test(x.url)); +const c = await CDP.connect(t.webSocketDebuggerUrl); +await c.send('Page.enable'); await c.send('Runtime.enable'); +await c.send('Page.navigate',{url:'https://erp.91miaoshou.com/common_collect_box/items'}); +await wait(12000); +// 找「关联货源」筛选控件 +const info = await c.evalJS(`(()=>{ + const labs=[...document.querySelectorAll('*')].filter(e=>e.children.length===0&&/关联货源/.test(e.innerText||'')); + if(!labs.length) return JSON.stringify({found:false}); + const lab=labs[0]; + let box=lab.parentElement; for(let i=0;i<4&&box;i++){ if(box.querySelector('input,.jx-select,[class*=select]')) break; box=box.parentElement; } + const ctl=box?box.querySelector('input,.jx-select,[class*=select]'):null; + const r=ctl?ctl.getBoundingClientRect():null; + return JSON.stringify({found:true, tag:ctl?ctl.tagName:'none', cls:ctl?String(ctl.className).slice(0,50):'', + txt:ctl?(ctl.innerText||ctl.value||'').slice(0,20):'', x:r?Math.round(r.x+r.width/2):0, y:r?Math.round(r.y+r.height/2):0});})()`); +console.log('筛选控件:', S(String(info)).slice(0,300)); +const o = JSON.parse(String(info)); +if (o.found && o.x) { + await c.send('Input.dispatchMouseEvent',{type:'mouseMoved',x:o.x,y:o.y,buttons:0}); await wait(300); + for(const tp of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type:tp,x:o.x,y:o.y,button:'left',clickCount:1,buttons:1}); + await wait(2500); + const opts = await c.evalJS(`(()=>{const dds=[...document.querySelectorAll('.jx-select-dropdown,.jx-dropdown,[class*=dropdown]')].filter(e=>e.offsetParent!==null); + const items=dds.flatMap(d=>[...d.querySelectorAll('li,.jx-select-dropdown__item,[class*=option]')].map(e=>(e.innerText||'').trim()).filter(Boolean)); + return JSON.stringify([...new Set(items)].slice(0,12));})()`); + console.log('货源选项:', S(String(opts)).slice(0,400)); + const picked = await c.evalJS(`(()=>{const dds=[...document.querySelectorAll('.jx-select-dropdown,.jx-dropdown,[class*=dropdown]')].filter(e=>e.offsetParent!==null); + for(const d of dds){ const it=[...d.querySelectorAll('li,.jx-select-dropdown__item,[class*=option]')].find(e=>/1688|全部/.test(e.innerText||'')); + if(it){ for(const ev of ['mousedown','mouseup','click']) it.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return 'picked:'+(it.innerText||'').trim(); } } return 'nf';})()`); + console.log('选择:', String(picked)); + await wait(6000); +} +const after = await c.evalJS(`(()=>{const body=(document.body.innerText||'').replace(/\\s+/g,' '); + const rows=[...document.querySelectorAll('tr')].filter(e=>e.offsetParent!==null).map(e=>(e.innerText||'').replace(/\\s+/g,' ').trim()).filter(Boolean); + const m=body.match(/共\\s*\\d+\\s*[条个]/); + return JSON.stringify({total:m?m[0]:'', rowCount:rows.length, first:rows.slice(0,3), empty:/暂无数据/.test(body)});})()`); +console.log('筛选后:', S(String(after)).slice(0,700)); +try{ await c.shot('/tmp/ms_filter.jpg'); console.log('shot ok'); }catch(e){} +process.exit(0); diff --git a/妙手建品/ms_more.mjs b/妙手建品/ms_more.mjs new file mode 100644 index 0000000..fbf937d --- /dev/null +++ b/妙手建品/ms_more.mjs @@ -0,0 +1,27 @@ +import { listPages, wait } from '/home/admin9webs/shein建品/sh_lib.mjs'; +import { CDP, SAN as S } from '/tmp/cdp3.mjs'; +const t = (await listPages()).find(x=>/91miaoshou/i.test(x.url)); +const c = await CDP.connect(t.webSocketDebuggerUrl); +await c.send('Page.enable'); await c.send('Runtime.enable'); +await c.send('Page.navigate',{url:'https://erp.91miaoshou.com/common_collect_box/index?fetchType=importCopy'}); +await wait(12000); +const pos = JSON.parse(String(await c.evalJS(`(()=>{ + const rows=[...document.querySelectorAll('tr')].filter(e=>e.offsetParent!==null&&/^\\s*ms2\\s/.test((e.innerText||'').trim())); + const row=rows[0]; if(!row) return '[]'; + const m=[...row.querySelectorAll('*')].find(e=>(e.innerText||'').trim()==='更多'&&e.children.length===0); + if(!m) return '[]'; m.scrollIntoView({block:'center'}); const r=m.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){ + await c.send('Input.dispatchMouseEvent',{type:'mouseMoved',x:pos[0],y:pos[1],buttons:0}); await wait(400); + for(const tp of ['mousePressed','mouseReleased']) await c.send('Input.dispatchMouseEvent',{type:tp,x:pos[0],y:pos[1],button:'left',clickCount:1,buttons:1}); +} +await wait(3000); +const o = await c.evalJS(`(()=>{ + const items=[...document.querySelectorAll('.jx-dropdown-menu li,.jx-dropdown-menu__item,[class*=dropdown] li,[class*=menu] li')] + .filter(e=>e.offsetParent!==null).map(e=>(e.innerText||'').trim()).filter(Boolean); + const any=[...document.querySelectorAll('*')].filter(e=>e.offsetParent!==null&&e.children.length===0&&/采集|认领|发布|下载|重试|删除|查看/.test(e.innerText||'')&&(e.innerText||'').length<12).map(e=>(e.innerText||'').trim()); + return JSON.stringify({menuItems:[...new Set(items)].slice(0,12), others:[...new Set(any)].slice(0,14)});})()`); +console.log('更多菜单:', S(String(o)).slice(0,600)); +try{ await c.shot('/tmp/ms_more.jpg'); console.log('shot ok'); }catch(e){} +process.exit(0);