diff --git a/scripts/zhaopin-scrape.js b/scripts/zhaopin-scrape.js index 15777b6..f3e997a 100755 --- a/scripts/zhaopin-scrape.js +++ b/scripts/zhaopin-scrape.js @@ -48,6 +48,30 @@ const CDP_PORT = process.env.CDP_PORT || '9222'; const ACCOUNT = process.env.ACCOUNT || 'hr1'; const TARGET_CITY = process.env.TARGET_CITY || '郑州'; const COMPANY_BLACKLIST = ['合塑', '派卡']; // 从 workDetail 提取公司名命中即跳过 + +// ---------- 个人黑名单(v10.13, 2026-09-29)---------- +// person_blacklist 表:用户指定的候选人,命中即不开弹窗直接跳过 +// 匹配规则:① 姓名=全名(弹窗里能看到全名)② 卡片场景兜底:姓+年龄一致(如"孟女士"+23岁) +// ③ resumeNumber 精确匹配(如有) +let PERSON_BLACKLIST = []; +function loadPersonBlacklist(db) { + try { + PERSON_BLACKLIST = db.prepare('SELECT resume_number, name, age FROM person_blacklist').all(); + if (PERSON_BLACKLIST.length) log(`个人黑名单已加载: ${PERSON_BLACKLIST.length} 人 [${PERSON_BLACKLIST.map(p => p.name).join('、')}]`); + } catch (e) { PERSON_BLACKLIST = []; } // 表不存在等异常不阻塞主流程 +} +function personBlackHit(cardName, cardAge, resumeNumber) { + for (const p of PERSON_BLACKLIST) { + if (p.resume_number && resumeNumber && p.resume_number === resumeNumber) return `${p.name}(精确ID)`; + if (cardName && p.name && cardName === p.name) return p.name; // 弹窗全名精确 + // 卡片"姓+称谓"场景:孟女士/孟先生 的姓 == 黑名单人姓 且年龄一致 + if (cardName && cardAge != null && p.name && p.age === cardAge + && /^(.)(女士|先生)/.test(cardName) && cardName.charAt(0) === p.name.charAt(0)) { + return `${p.name}(姓+年龄匹配)`; + } + } + return null; +} const MAX_START_SKIP = 50; // ---------- 工具 ---------- @@ -349,6 +373,7 @@ async function scrapeZhaopin(maxCount = 20, fullMode = false, scoreOnly = false) if (!page) { console.log('ERROR: 未找到推荐页面(需在浏览器中打开 recommend 页)'); await browser.close(); process.exit(1); } const db = initDB(); + loadPersonBlacklist(db); // v10.13:个人黑名单 const existingIds = new Set(db.prepare('SELECT id FROM candidates').all().map(r => r.id)); // 启动快速跳过用的卡片指纹(name|age|education|experience,来自历史 card_info) const storedCards = new Set(db.prepare("SELECT card_info FROM candidates WHERE card_info IS NOT NULL").all() @@ -446,6 +471,10 @@ async function scrapeZhaopin(maxCount = 20, fullMode = false, scoreOnly = false) const cardBlackHit = COMPANY_BLACKLIST.find(b => card.cardText && card.cardText.includes(b)); if (cardBlackHit) { log(`🚫 [跳过-列表黑名单] ${card.name} | 卡片含"${cardBlackHit}"`); skipped++; currentDataIndex = await navigateToNextCard(page, currentDataIndex); continue; } + // v10.13:个人黑名单(卡片级:姓+年龄)——不开弹窗直接跳过 + const pBlackHit = personBlackHit(card.name, card.age, null); + if (pBlackHit) { log(`🚫 [跳过-个人黑名单] ${card.name} ${card.age}岁 | 命中: ${pBlackHit}`); skipped++; currentDataIndex = await navigateToNextCard(page, currentDataIndex); continue; } + try { // 打开弹窗(v10.12:Playwright原生点击替代evaluate合成click——平台反自动化检测会 // 对合成点击返回空白弹窗;原生点击走真实鼠标事件流 CDP Input.dispatchMouseEvent)