aliChoice:类目 dry 扫描(47/47 避开强制说明书类目)+ 批量读 alc_route.json;记录 SKU分类/材质/尺寸 两类新失败
This commit is contained in:
1 parent
a5c32e4726
commit
de9d988f4c
5 files changed
+351
-10
No files matched your search
@@ -75,7 +75,7 @@ function wrap(o,n,l){const f=o[n];o[n]=function(){window.__cap.push(l+': '+[...a
|
||||
| 平台 | add 路由 | 店铺控件 | 类目控件 | store 家族 |
|
||||
|---|---|---|---|---|
|
||||
| Joom | `/web/joomProduct/add` | **复选框组** 85 个(全部+84 店) | 可搜索 `.ant-select` 平铺列表 | `smtChoice*` + `joom*`(已跑通) |
|
||||
| aliChoice | `/web/smtChoice/add` | 下拉(实测 2 家) | 弹窗 | `smtChoice*`:标题 `.subject`、描述要写 **CKEditor setData**、保存要**两遍**(第二遍前补「物流属性=普货」)——**已跑通**,`alcbatch.mjs` 批量中 |
|
||||
| aliChoice | `/web/smtChoice/add` | 下拉(实测 2 家) | 弹窗 | `smtChoice*`:标题 `.subject`、描述要写 **CKEditor setData**、保存要**两遍**(第二遍前补「物流属性=普货」)——**已跑通**;类目要先 `alcdry.mjs` dry 扫一遍(避开强制「商品说明书」的类目,结果写 `alc_route.json`),再 `alcbatch.mjs` 批量。剩余卡点:`请选择SKU分类`、类目属性 `材质/尺寸` 选了不生效 |
|
||||
| Lazada | `/web/lazada/add` | 下拉 | 弹窗 | 选完店铺才注册 `lazada*` store(懒加载) |
|
||||
| fruugo | `/web/fruugoProduct/add` | 下拉 | 弹窗 | `fruugoAdd*`(Common/Basic/Dxm/Product/Variation/Image/Describe/Form) |
|
||||
|
||||
|
||||
@@ -79,3 +79,20 @@ pinia._s.get('smtChoiceAddStore').$state.describeInfoData.detail = html;
|
||||
把落到健康/医疗/化妆品等强资质类目的商品挑出来,再决定是换词还是跳过。
|
||||
|
||||
失败记录现在会带 `errItems`(例如 `商品说明书:请上传文件!`),见 `alc_done.json`。
|
||||
|
||||
---
|
||||
|
||||
## 第二次批量(带 dry 扫描出来的类目表)进展与新的失败类
|
||||
|
||||
`alcdry.mjs` 先扫类目(不保存),把每个商品**第一个不强制「商品说明书」**的品类词写进
|
||||
`alc_route.json`(47/47 都有可用类目;例:温度计「温度计」强制说明书 → 回退到「家用电器」`说明书=否`)。
|
||||
`alcbatch.mjs` 之后只读这张表,不再猜类目。
|
||||
|
||||
**结果**:`商品说明书` 类失败归零;但冒出两类**新的必填**(都是类目动态属性/SKU 级):
|
||||
|
||||
| 现象(`errItems`) | 猜测与下一步 |
|
||||
|---|---|
|
||||
| `(无label):请选择SKU分类` | SKU 行上有个 **SKU分类** 下拉要选(Temu 的 SKU 表也有这一列)。下一步:定位它的落点(可能 `skuDataList[].skuClassification`)或走 UI 选第一项 |
|
||||
| `材质(Material):` / `尺寸(Size):` | 类目动态属性里**把下拉当文本**的项,`fillRequiredSelects` 选了但值没生效(红色提示为空)→ 下一步 dump 这两项的控件类型(可能是可搜索 select 或 input) |
|
||||
|
||||
成材率从 2/6 提升到 5/8,其余靠这两类补齐。
|
||||
@@ -0,0 +1,237 @@
|
||||
{
|
||||
"548459586741": {
|
||||
"cat": "口哨",
|
||||
"path": "运动及娱乐(Sports & Entertainment)/团队运动(Team Sports)/啦啦队用品及纪念品(Ch",
|
||||
"needsManual": false
|
||||
},
|
||||
"661190598139": {
|
||||
"cat": "发饰",
|
||||
"path": "服饰配饰(男/女/儿童配件,婴儿配饰发到婴儿服装)(Apparel Accessories)/发饰(New Headwe",
|
||||
"needsManual": false
|
||||
},
|
||||
"764423265986": {
|
||||
"cat": "家用电器",
|
||||
"path": "家用电器(Home Appliances)/家电零部件(Home Appliance Parts)/3合一早餐机零部件(",
|
||||
"needsManual": false
|
||||
},
|
||||
"685456757807": {
|
||||
"cat": "毛线",
|
||||
"path": "家居用品(Home & Garden)/手工艺品&缝纫用品(半成品)(Arts,Crafts & Sewing)/毛线编",
|
||||
"needsManual": false
|
||||
},
|
||||
"735147938123": {
|
||||
"cat": "发箍",
|
||||
"path": "接发与发套(Hair Extensions & Wigs)/亚洲假发(Hair For Asian)/亚洲化纤发(Syn",
|
||||
"needsManual": false
|
||||
},
|
||||
"627879474686": {
|
||||
"cat": "袜子",
|
||||
"path": "新奇特及特殊用途服装(Novelty & Special Use)/舞台表演服和舞蹈服(Stage & Dance We",
|
||||
"needsManual": false
|
||||
},
|
||||
"610164857063": {
|
||||
"cat": "发带",
|
||||
"path": "接发与发套(Hair Extensions & Wigs)/美发沙龙工具及配件(Hair Tools & Accesso",
|
||||
"needsManual": false
|
||||
},
|
||||
"676236596821": {
|
||||
"cat": "发夹",
|
||||
"path": "接发与发套(Hair Extensions & Wigs)/美发沙龙工具及配件(Hair Tools & Accesso",
|
||||
"needsManual": false
|
||||
},
|
||||
"708420302844": {
|
||||
"cat": "钥匙扣",
|
||||
"path": "玩具(Toys & Hobbies)/填充动物/毛绒玩具(Stuffed Animals & Plush)/毛绒玩具钥匙",
|
||||
"needsManual": false
|
||||
},
|
||||
"866537106657": {
|
||||
"cat": "纽扣",
|
||||
"path": "家居用品(Home & Garden)/手工艺品&缝纫用品(半成品)(Arts,Crafts & Sewing)/DIY",
|
||||
"needsManual": false
|
||||
},
|
||||
"547183997437": {
|
||||
"cat": "项链",
|
||||
"path": "珠宝饰品及配件(Jewelry & Accessories)/精品珠宝(Fine Jewelry)/项链(Necklac",
|
||||
"needsManual": false
|
||||
},
|
||||
"657617635303": {
|
||||
"cat": "收纳盒",
|
||||
"path": "家居用品(Home & Garden)/家用储存收藏用具(Home Storage & Organization)/衣物",
|
||||
"needsManual": false
|
||||
},
|
||||
"641673262387": {
|
||||
"cat": "收纳袋",
|
||||
"path": "家居用品(Home & Garden)/家用储存收藏用具(Home Storage & Organization)/收纳",
|
||||
"needsManual": false
|
||||
},
|
||||
"953869908708": {
|
||||
"cat": "贴纸",
|
||||
"path": "消费电子(Consumer Electronics)/游戏及配附件(Games & Accessories)/贴纸(St",
|
||||
"needsManual": false
|
||||
},
|
||||
"703822717997": {
|
||||
"cat": "文具",
|
||||
"path": "图书和文化衍生用品(Books & Cultural Merchandise)/文化衍生品(办公文具)(Cultural",
|
||||
"needsManual": false
|
||||
},
|
||||
"863524134410": {
|
||||
"cat": "贴纸",
|
||||
"path": "消费电子(Consumer Electronics)/游戏及配附件(Games & Accessories)/贴纸(St",
|
||||
"needsManual": false
|
||||
},
|
||||
"694637537727": {
|
||||
"cat": "收纳袋",
|
||||
"path": "家居用品(Home & Garden)/家用储存收藏用具(Home Storage & Organization)/收纳",
|
||||
"needsManual": false
|
||||
},
|
||||
"623011262210": {
|
||||
"cat": "贴纸",
|
||||
"path": "消费电子(Consumer Electronics)/游戏及配附件(Games & Accessories)/贴纸(St",
|
||||
"needsManual": false
|
||||
},
|
||||
"836512561982": {
|
||||
"cat": "化妆包",
|
||||
"path": "箱包(Luggage & Bags)/特殊用途箱包(Special Purpose Bags)/化妆包(Cosmetic",
|
||||
"needsManual": false
|
||||
},
|
||||
"714492799386": {
|
||||
"cat": "化妆包",
|
||||
"path": "箱包(Luggage & Bags)/特殊用途箱包(Special Purpose Bags)/化妆包(Cosmetic",
|
||||
"needsManual": false
|
||||
},
|
||||
"591994902720": {
|
||||
"cat": "笔袋",
|
||||
"path": "办公、文化及教育用品(Office & School Supplies)/学生用品(School Supplies)/笔",
|
||||
"needsManual": false
|
||||
},
|
||||
"853414558425": {
|
||||
"cat": "手机挂绳",
|
||||
"path": "手机通讯配件(Phones & Telecommunications Accessories)/手机饰品(Mobile ",
|
||||
"needsManual": false
|
||||
},
|
||||
"997450831819": {
|
||||
"cat": "贴纸",
|
||||
"path": "消费电子(Consumer Electronics)/游戏及配附件(Games & Accessories)/贴纸(St",
|
||||
"needsManual": false
|
||||
},
|
||||
"639409307567": {
|
||||
"cat": "墙贴",
|
||||
"path": "家居用品(Home & Garden)/家庭装饰品(Home Decor)/家居装饰贴纸(Home Decoration",
|
||||
"needsManual": false
|
||||
},
|
||||
"902440558099": {
|
||||
"cat": "发饰",
|
||||
"path": "服饰配饰(男/女/儿童配件,婴儿配饰发到婴儿服装)(Apparel Accessories)/发饰(New Headwe",
|
||||
"needsManual": false
|
||||
},
|
||||
"823838532886": {
|
||||
"cat": "卡套",
|
||||
"path": "办公、文化及教育用品(Office & School Supplies)/笔记本、拍纸本等书写用品(Notebooks ",
|
||||
"needsManual": false
|
||||
},
|
||||
"698782391248": {
|
||||
"cat": "贴纸",
|
||||
"path": "消费电子(Consumer Electronics)/游戏及配附件(Games & Accessories)/贴纸(St",
|
||||
"needsManual": false
|
||||
},
|
||||
"707826905566": {
|
||||
"cat": "卡包",
|
||||
"path": "箱包(Luggage & Bags)/钱包&卡包(Wallets & Holders)/卡包(Card & ID Hol",
|
||||
"needsManual": false
|
||||
},
|
||||
"1027332215847": {
|
||||
"cat": "收纳盒",
|
||||
"path": "家居用品(Home & Garden)/家用储存收藏用具(Home Storage & Organization)/衣物",
|
||||
"needsManual": false
|
||||
},
|
||||
"682195499823": {
|
||||
"cat": "笔袋",
|
||||
"path": "办公、文化及教育用品(Office & School Supplies)/学生用品(School Supplies)/笔",
|
||||
"needsManual": false
|
||||
},
|
||||
"823560564174": {
|
||||
"cat": "发饰",
|
||||
"path": "服饰配饰(男/女/儿童配件,婴儿配饰发到婴儿服装)(Apparel Accessories)/发饰(New Headwe",
|
||||
"needsManual": false
|
||||
},
|
||||
"739147684759": {
|
||||
"cat": "纽扣",
|
||||
"path": "家居用品(Home & Garden)/手工艺品&缝纫用品(半成品)(Arts,Crafts & Sewing)/DIY",
|
||||
"needsManual": false
|
||||
},
|
||||
"621300323670": {
|
||||
"cat": "胶带座",
|
||||
"path": "办公、文化及教育用品(Office & School Supplies)/胶带、胶水、包装带等(Tapes, Adhes",
|
||||
"needsManual": false
|
||||
},
|
||||
"896469995553": {
|
||||
"cat": "钥匙扣",
|
||||
"path": "玩具(Toys & Hobbies)/填充动物/毛绒玩具(Stuffed Animals & Plush)/毛绒玩具钥匙",
|
||||
"needsManual": false
|
||||
},
|
||||
"944470567338": {
|
||||
"cat": "发夹",
|
||||
"path": "接发与发套(Hair Extensions & Wigs)/美发沙龙工具及配件(Hair Tools & Accesso",
|
||||
"needsManual": false
|
||||
},
|
||||
"787261097583": {
|
||||
"cat": "发夹",
|
||||
"path": "接发与发套(Hair Extensions & Wigs)/美发沙龙工具及配件(Hair Tools & Accesso",
|
||||
"needsManual": false
|
||||
},
|
||||
"833753630925": {
|
||||
"cat": "发箍",
|
||||
"path": "接发与发套(Hair Extensions & Wigs)/亚洲假发(Hair For Asian)/亚洲化纤发(Syn",
|
||||
"needsManual": false
|
||||
},
|
||||
"719391062058": {
|
||||
"cat": "收纳盒",
|
||||
"path": "家居用品(Home & Garden)/家用储存收藏用具(Home Storage & Organization)/衣物",
|
||||
"needsManual": false
|
||||
},
|
||||
"857781294719": {
|
||||
"cat": "发夹",
|
||||
"path": "接发与发套(Hair Extensions & Wigs)/美发沙龙工具及配件(Hair Tools & Accesso",
|
||||
"needsManual": false
|
||||
},
|
||||
"863384503032": {
|
||||
"cat": "发夹",
|
||||
"path": "接发与发套(Hair Extensions & Wigs)/美发沙龙工具及配件(Hair Tools & Accesso",
|
||||
"needsManual": false
|
||||
},
|
||||
"774494945453": {
|
||||
"cat": "钥匙扣",
|
||||
"path": "玩具(Toys & Hobbies)/填充动物/毛绒玩具(Stuffed Animals & Plush)/毛绒玩具钥匙",
|
||||
"needsManual": false
|
||||
},
|
||||
"750271307455": {
|
||||
"cat": "钥匙扣",
|
||||
"path": "玩具(Toys & Hobbies)/填充动物/毛绒玩具(Stuffed Animals & Plush)/毛绒玩具钥匙",
|
||||
"needsManual": false
|
||||
},
|
||||
"726442972676": {
|
||||
"cat": "发夹",
|
||||
"path": "接发与发套(Hair Extensions & Wigs)/美发沙龙工具及配件(Hair Tools & Accesso",
|
||||
"needsManual": false
|
||||
},
|
||||
"775057912118": {
|
||||
"cat": "钥匙扣",
|
||||
"path": "玩具(Toys & Hobbies)/填充动物/毛绒玩具(Stuffed Animals & Plush)/毛绒玩具钥匙",
|
||||
"needsManual": false
|
||||
},
|
||||
"893592264148": {
|
||||
"cat": "发夹",
|
||||
"path": "接发与发套(Hair Extensions & Wigs)/美发沙龙工具及配件(Hair Tools & Accesso",
|
||||
"needsManual": false
|
||||
},
|
||||
"607330049419": {
|
||||
"cat": "发饰",
|
||||
"path": "服饰配饰(男/女/儿童配件,婴儿配饰发到婴儿服装)(Apparel Accessories)/发饰(New Headwe",
|
||||
"needsManual": false
|
||||
},
|
||||
"854003999648": {
|
||||
"cat": "发饰",
|
||||
"path": "服饰配饰(男/女/儿童配件,婴儿配饰发到婴儿服装)(Apparel Accessories)/发饰(New Headwe",
|
||||
"needsManual": false
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ const only = argv.filter(a => !a.startsWith('--'));
|
||||
let tasks = Object.keys(INPUT).filter(pid => (INPUT[pid].imgs || []).length > 0).map(pid => ({ pid }));
|
||||
if (only.length) tasks = tasks.filter(t => only.includes(t.pid)); else tasks = tasks.filter(t => !SKIP.has(t.pid));
|
||||
let done = {}; try { done = JSON.parse(readFileSync(DONE_F, 'utf8')); } catch {}
|
||||
let ROUTE = {}; try { ROUTE = JSON.parse(readFileSync(`${DIR}/alc_route.json`, 'utf8')); } catch {}
|
||||
const log = m => { const l = `[${new Date().toISOString().slice(11, 19)}] ${m}`; console.log(l); appendFileSync(LOG_F, l + '\n'); };
|
||||
|
||||
/** PC端描述:真实控件是 CKEditor(隐藏 textarea + 所见即所得),给编辑器实例 setData 才有效 */
|
||||
@@ -109,15 +110,17 @@ for (const t of tasks) {
|
||||
await wait(6000);
|
||||
log(` 备货类型: ${await pickFirstOption(c, '备货类型')}`);
|
||||
await wait(3000);
|
||||
// 类目:cat_kw 搜不到就依次试 cat_fb(tk_input 里给的后备品类词)
|
||||
let cat = await selectCategory(c, it.cat_kw || '发夹', it.cat_kw);
|
||||
if (!String(cat).startsWith('path:')) {
|
||||
for (const fb of (it.cat_fb || []).slice(0, 3)) {
|
||||
cat = await selectCategory(c, fb, fb);
|
||||
if (String(cat).startsWith('path:')) { log(` 类目回退到「${fb}」`); break; }
|
||||
}
|
||||
// 类目:用 alcdry.mjs 扫出来的词(已确认该词落到的类目不强制「商品说明书」)
|
||||
const rc = ROUTE[t.pid];
|
||||
if (!rc || !rc.cat) {
|
||||
log(` ⏭ 跳过:没有不要求资质文件的类目(dry 扫描结论)`);
|
||||
done[t.pid] = { ok: false, skipped: true, msg: '无可用类目:全部候选都强制商品说明书' };
|
||||
await closePage(c); c = null;
|
||||
if (!dry) writeFileSync(DONE_F, JSON.stringify(done, null, 1));
|
||||
continue;
|
||||
}
|
||||
log(` 类目: ${String(cat).slice(0, 110)}`);
|
||||
const cat = await selectCategory(c, rc.cat, rc.cat);
|
||||
log(` 类目: 「${rc.cat}」 ${String(cat).slice(0, 90)}`);
|
||||
if (!String(cat).startsWith('path:')) throw new Error('选类目失败:' + cat);
|
||||
await wait(6000);
|
||||
const fill = await c.evalJS(`(()=>{const p=${P}; const imgs=${JSON.stringify((it.imgs || []).slice(0, 6))};
|
||||
@@ -156,7 +159,7 @@ for (const t of tasks) {
|
||||
const red=[...x.querySelectorAll('.text-red-500')].map(e=>(e.innerText||'').trim().slice(0,30)).filter(Boolean);
|
||||
return t+':'+red.join('/');}).slice(0,6))`));
|
||||
const ok = /已保存|保存成功|待发布/.test(mods);
|
||||
done[t.pid] = ok ? { ok: true } : { ok: false, errItems: errItems.slice(0, 260), mods: mods.slice(0, 120), hook: String(cap).slice(-200) };
|
||||
done[t.pid] = ok ? { ok: true, cat: rc.cat, path: rc.path } : { ok: false, cat: rc.cat, errItems: errItems.slice(0, 260), mods: mods.slice(0, 120), hook: String(cap).slice(-200) };
|
||||
log(ok ? ' ✓ 已保存到待发布' : ` ✗ 失败 ${mods.slice(0, 110)} | ${String(cap).slice(-170)}`);
|
||||
} catch (e) {
|
||||
done[t.pid] = { ok: false, msg: String(e).slice(0, 240) };
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* aliChoice 类目 dry 扫描(不保存)
|
||||
* 对每个商品:cat_kw 起,逐次回退 cat_fb —— 选中后检查类目是否**强制商品说明书**,
|
||||
* 取第一个不强制说明书的词;全都强制就标 needsManual。
|
||||
* 结果写 alc_route.json,供 alcbatch.mjs 直接使用(避免重跑时再猜类目)。
|
||||
*/
|
||||
import { readFileSync, writeFileSync, appendFileSync } from 'fs';
|
||||
import { newPage, closePage, wait } from '/home/admin9webs/shein建品/sh_lib.mjs';
|
||||
import { selectCategory } from '/home/admin9webs/shein建品/sh_build.mjs';
|
||||
|
||||
const DIR = '/home/admin9webs/alichoice建品';
|
||||
const INPUT = JSON.parse(readFileSync('/home/admin9webs/tiktok建品/tk_input.json', 'utf8'));
|
||||
const OUT = `${DIR}/alc_route.json`;
|
||||
const LOG = `${DIR}/alc_dry.log`;
|
||||
const SKIP = new Set(['601964534137']);
|
||||
const log = m => { const l = `[${new Date().toISOString().slice(11, 19)}] ${m}`; console.log(l); appendFileSync(LOG, l + '\n'); };
|
||||
|
||||
let route = {}; try { route = JSON.parse(readFileSync(OUT, 'utf8')); } catch {}
|
||||
|
||||
async function pickFirstOption(c, labelRe) {
|
||||
const p = JSON.parse(String(await c.evalJS(`(()=>{const f=[...document.querySelectorAll('.ant-form-item')].filter(e=>e.offsetParent!==null)
|
||||
.find(e=>new RegExp(${JSON.stringify(labelRe)}).test((e.querySelector('label')||{}).innerText||''));
|
||||
const s=f?f.querySelector('.ant-select-selector'):null; 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)]);})()`)));
|
||||
if (!p.length) return 'no-sel';
|
||||
await c.send('Input.dispatchMouseEvent', { type: 'mouseMoved', x: p[0], y: p[1], buttons: 0 }); await wait(250);
|
||||
for (const t of ['mousePressed', 'mouseReleased'])
|
||||
await c.send('Input.dispatchMouseEvent', { type: t, x: p[0], y: p[1], button: 'left', clickCount: 1, buttons: 1 });
|
||||
await wait(1800);
|
||||
return c.evalJS(`(()=>{const dd=[...document.querySelectorAll('.ant-select-dropdown')].filter(e=>e.offsetParent!==null).pop();
|
||||
if(!dd) return 'no-dd'; const op=[...dd.querySelectorAll('.ant-select-item-option')].filter(e=>e.offsetParent!==null)[0]; if(!op) return 'no-op';
|
||||
const r=op.getBoundingClientRect();
|
||||
for(const ev of ['mousedown','mouseup','click']) op.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window,clientX:r.x+r.width/2,clientY:r.y+r.height/2}));
|
||||
return 'picked:'+(op.innerText||'').trim().slice(0,14);})()`);
|
||||
}
|
||||
|
||||
/** 类目选中后,看表单里有没有「商品说明书」这类强制文件项 */
|
||||
async function needsManual(c) {
|
||||
return c.evalJS(`(()=>{
|
||||
for (const e of document.querySelectorAll('.ant-form-item')) {
|
||||
if (e.offsetParent === null) continue;
|
||||
const t = (e.innerText || '');
|
||||
if (!/商品说明书|说明书/.test(t)) continue;
|
||||
const lab = e.querySelector('label');
|
||||
const req = (lab && /required/.test(String(lab.className))) || e.querySelector('.attr-label.required') || /请上传文件/.test(t);
|
||||
if (req) return 1;
|
||||
}
|
||||
return 0;})()`);
|
||||
}
|
||||
|
||||
const pids = Object.keys(INPUT).filter(p => (INPUT[p].imgs || []).length > 0).filter(p => !SKIP.has(p));
|
||||
log(`aliChoice 类目 dry 扫描:${pids.length} 条`);
|
||||
for (const pid of pids) {
|
||||
if (route[pid] && route[pid].cat) { log(`跳过 ${pid}(已有 ${route[pid].cat})`); continue; }
|
||||
const it = INPUT[pid];
|
||||
let c;
|
||||
try {
|
||||
c = await newPage('https://www.dianxiaomi.com/web/smtChoice/add');
|
||||
await wait(11000);
|
||||
await pickFirstOption(c, '店铺名称'); await wait(5500);
|
||||
await pickFirstOption(c, '备货类型'); await wait(2500);
|
||||
const cands = [it.cat_kw, ...(it.cat_fb || [])].filter(Boolean).slice(0, 6);
|
||||
let chosen = null;
|
||||
for (const kw of cands) {
|
||||
const r = String(await selectCategory(c, kw, kw));
|
||||
await wait(3500);
|
||||
if (!r.startsWith('path:')) { log(` ${pid} 「${kw}」无结果`); continue; }
|
||||
const nm = await needsManual(c);
|
||||
log(` ${pid} 「${kw}」 → ${r.slice(5, 60)} 说明书=${nm ? '强制' : '否'}`);
|
||||
if (!nm) { chosen = { cat: kw, path: r.slice(5, 90), needsManual: false }; break; }
|
||||
}
|
||||
route[pid] = chosen || { cat: null, needsManual: true, tried: cands };
|
||||
writeFileSync(OUT, JSON.stringify(route, null, 1));
|
||||
} catch (e) {
|
||||
log(` ${pid} 异常: ${String(e).slice(0, 120)}`);
|
||||
route[pid] = { cat: null, error: String(e).slice(0, 120) };
|
||||
writeFileSync(OUT, JSON.stringify(route, null, 1));
|
||||
} finally {
|
||||
if (c) await closePage(c);
|
||||
await wait(1500);
|
||||
}
|
||||
}
|
||||
const okN = Object.values(route).filter(v => v.cat).length;
|
||||
log(`dry 扫描结束:可用类目 ${okN} / ${pids.length},需人工 ${Object.values(route).filter(v => v.needsManual).length}`);
|
||||
Reference in new issue
Block a user