v1.2 登录监听自动复工: 登录失效/被顶号告警后每30秒检测扫码(最多至北京17:30), 检测到登录成功自动重启筛选批次, 无需人工再叫启动

This commit is contained in:
hermes
2026-08-27 03:27:21 +00:00
parent d0dbe9c676
commit f62df26ec0
+47 -9
View File
@@ -33,7 +33,7 @@ const log = (m) => console.log(`[daily-runner ${ACCT}] ${new Date().toISOString(
// ---------- 工具 ----------
const bjNow = () => new Date(Date.now() + 8 * 3600 * 1000); // 北京时间
const bjHm = () => { const d = bjNow(); return d.getUTCHours() * 60 + d.getUTCMinutes(); };
const pastCutoff = () => bjHm() >= 18 * 60; // 北京 18:00
const pastCutoff = (atMin = 18 * 60) => bjHm() >= atMin; // 默认北京 18:00,可传其它时刻
const today = () => bjNow().toISOString().slice(0, 10);
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
const randInt = (a, b) => a + Math.floor(Math.random() * (b - a + 1));
@@ -171,6 +171,33 @@ function statusText(s) {
return '✅ 在线';
}
// 登录监听:告警发出后每30秒检查登录页是否已被扫码登录(跳回推荐页/出现卡片)
// 监听到登录成功 → 自动重启筛选批次;17:30 后不再等(留给18:05收队收尾)
async function waitForRelogin() {
const pw = require('playwright-core');
log('进入登录监听(每30秒检测扫码,最多等到北京17:30)...');
writeState('waiting_relogin', null);
while (!fs.existsSync(STOP_FLAG) && !pastCutoff(17.5 * 60)) {
await new Promise(r => setTimeout(r, 30000));
let logged = false;
try {
const b = await pw.chromium.connectOverCDP(`http://127.0.0.1:${PORT}`);
const p = b.contexts()[0]?.pages().find(x => /zhaopin\.com/.test(x.url()));
if (p) {
logged = await p.evaluate(() =>
!location.href.includes('passport') &&
!/账号已在其他设备或浏览器登录/.test(document.body?.innerText || '') &&
document.querySelectorAll('.recommend-item').length > 0
).catch(() => false);
}
try { await b.close(); } catch (_) {}
} catch (_) { /* CDP暂时不通就下轮再查 */ }
if (logged) { log('🎉 检测到已扫码登录,自动复工'); return true; }
}
log('登录监听结束(到时或被叫停),今日不再复工');
return false;
}
// ---------- 主流程 ----------
(async () => {
log(`启动 | 端口${PORT} | 库${DB} | 截止北京18:00`);
@@ -187,6 +214,8 @@ function statusText(s) {
}
let lastChatLeft = null, zeroStreak = 0;
let needRelogin = false; // v1.2:登录类异常(登录失效/被顶号)→ 告警后进监听等扫码,扫完自动复工
while (true) {
// v1.1:随时叫停——每轮检查停止旗标,优雅退出(不发日报不发告警,等重启或18点兜底)
if (fs.existsSync(STOP_FLAG)) {
@@ -198,25 +227,34 @@ function statusText(s) {
const { code, out } = await runBatch();
// 被顶号(账号在其他设备登录)→ 群告警+二维码(会话已被踢,重新登录同样需要扫码),立即结束(2026-08-27)
// 被顶号(账号在其他设备登录)→ 群告警+二维码,进登录监听(2026-08-27)
if (/账号被顶/.test(out)) {
await notifyKickedOut(lastChatLeft);
break;
needRelogin = true;
}
// 登录失效 → 群告警(带登录二维码),结束
if (/登录已失效|passport\.zhaopin\.com/.test(out)) {
// 登录失效 → 群告警(带登录二维码),进登录监听
else if (/登录已失效|passport\.zhaopin\.com/.test(out)) {
notifyLoginExpired();
maybeSendReport('login_expired', lastChatLeft);
break;
needRelogin = true;
}
// 风控/验证码 → 私聊告警,结束
if (/ALERT.*(风控|验证|频繁|受限)/.test(out)) {
// 风控/验证码 → 私聊告警,结束(不监听,风控需人工评估)
else if (/ALERT.*(风控|验证|频繁|受限)/.test(out)) {
send(DM, `🚨 ${ACCT} 触发风控/验证码(${(out.match(/ALERT[::][^\n]*/) || ['未知原因'])[0]}),今日筛选中止`);
maybeSendReport('alert', lastChatLeft);
break;
}
// 聊天耗尽 → 结束
if (/聊天次数耗尽/.test(out)) { log('聊天次数耗尽,收工'); maybeSendReport('chat_exhausted', 0); break; }
else if (/聊天次数耗尽/.test(out)) { log('聊天次数耗尽,收工'); maybeSendReport('chat_exhausted', 0); break; }
// v1.2:登录类异常 → 监听扫码,登录成功自动复工;没登录就今日收工
if (needRelogin) {
needRelogin = false;
const relogged = await waitForRelogin();
if (!relogged) break;
writeState('running', lastChatLeft); // 复工
continue;
}
// 解析剩余次数
const m = [...out.matchAll(/聊天剩余[::]?\s*(\d+)\s*次/g)].pop();