v1.2 登录监听自动复工: 登录失效/被顶号告警后每30秒检测扫码(最多至北京17:30), 检测到登录成功自动重启筛选批次, 无需人工再叫启动
This commit is contained in:
+47
-9
@@ -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 bjNow = () => new Date(Date.now() + 8 * 3600 * 1000); // 北京时间
|
||||||
const bjHm = () => { const d = bjNow(); return d.getUTCHours() * 60 + d.getUTCMinutes(); };
|
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 today = () => bjNow().toISOString().slice(0, 10);
|
||||||
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
||||||
const randInt = (a, b) => a + Math.floor(Math.random() * (b - a + 1));
|
const randInt = (a, b) => a + Math.floor(Math.random() * (b - a + 1));
|
||||||
@@ -171,6 +171,33 @@ function statusText(s) {
|
|||||||
return '✅ 在线';
|
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 () => {
|
(async () => {
|
||||||
log(`启动 | 端口${PORT} | 库${DB} | 截止北京18:00`);
|
log(`启动 | 端口${PORT} | 库${DB} | 截止北京18:00`);
|
||||||
@@ -187,6 +214,8 @@ function statusText(s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let lastChatLeft = null, zeroStreak = 0;
|
let lastChatLeft = null, zeroStreak = 0;
|
||||||
|
let needRelogin = false; // v1.2:登录类异常(登录失效/被顶号)→ 告警后进监听等扫码,扫完自动复工
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// v1.1:随时叫停——每轮检查停止旗标,优雅退出(不发日报不发告警,等重启或18点兜底)
|
// v1.1:随时叫停——每轮检查停止旗标,优雅退出(不发日报不发告警,等重启或18点兜底)
|
||||||
if (fs.existsSync(STOP_FLAG)) {
|
if (fs.existsSync(STOP_FLAG)) {
|
||||||
@@ -198,25 +227,34 @@ function statusText(s) {
|
|||||||
|
|
||||||
const { code, out } = await runBatch();
|
const { code, out } = await runBatch();
|
||||||
|
|
||||||
// 被顶号(账号在其他设备登录)→ 群告警+二维码(会话已被踢,重新登录同样需要扫码),立即结束(2026-08-27)
|
// 被顶号(账号在其他设备登录)→ 群告警+二维码,进登录监听(2026-08-27)
|
||||||
if (/账号被顶/.test(out)) {
|
if (/账号被顶/.test(out)) {
|
||||||
await notifyKickedOut(lastChatLeft);
|
await notifyKickedOut(lastChatLeft);
|
||||||
break;
|
needRelogin = true;
|
||||||
}
|
}
|
||||||
// 登录失效 → 群告警(带登录二维码),结束
|
// 登录失效 → 群告警(带登录二维码),进登录监听
|
||||||
if (/登录已失效|passport\.zhaopin\.com/.test(out)) {
|
else if (/登录已失效|passport\.zhaopin\.com/.test(out)) {
|
||||||
notifyLoginExpired();
|
notifyLoginExpired();
|
||||||
maybeSendReport('login_expired', lastChatLeft);
|
maybeSendReport('login_expired', lastChatLeft);
|
||||||
break;
|
needRelogin = true;
|
||||||
}
|
}
|
||||||
// 风控/验证码 → 私聊告警,结束
|
// 风控/验证码 → 私聊告警,结束(不监听,风控需人工评估)
|
||||||
if (/ALERT.*(风控|验证|频繁|受限)/.test(out)) {
|
else if (/ALERT.*(风控|验证|频繁|受限)/.test(out)) {
|
||||||
send(DM, `🚨 ${ACCT} 触发风控/验证码(${(out.match(/ALERT[::][^\n]*/) || ['未知原因'])[0]}),今日筛选中止`);
|
send(DM, `🚨 ${ACCT} 触发风控/验证码(${(out.match(/ALERT[::][^\n]*/) || ['未知原因'])[0]}),今日筛选中止`);
|
||||||
maybeSendReport('alert', lastChatLeft);
|
maybeSendReport('alert', lastChatLeft);
|
||||||
break;
|
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();
|
const m = [...out.matchAll(/聊天剩余[::]?\s*(\d+)\s*次/g)].pop();
|
||||||
|
|||||||
Reference in New Issue
Block a user