登录失效告警升级: 自动刷新页面抓登录二维码发群(文字+二维码图片+'今日不需要可忽略'说明), 失败降级纯文字
This commit is contained in:
+29
-2
@@ -47,6 +47,33 @@ function send(target, text) {
|
||||
} catch (e) { log(`发送失败: ${String(e.message).slice(0, 100)}`); }
|
||||
}
|
||||
|
||||
// 发送图片+文字到群(MEDIA: 语法)
|
||||
function sendGroupImage(text, imgPath) {
|
||||
try {
|
||||
fs.writeFileSync(`/tmp/runner-imgmsg-${ACCT}.txt`, `${text}\nMEDIA:${imgPath}`);
|
||||
execSync(`${HERMES} send -t "feishu:${GROUP}" -f /tmp/runner-imgmsg-${ACCT}.txt`,
|
||||
{ stdio: ['pipe', 'pipe', 'pipe'], timeout: 90000 });
|
||||
log(`已发送图片消息 → 群(数字HR)(附二维码)`);
|
||||
} catch (e) { log(`图片消息发送失败: ${String(e.message).slice(0, 100)}`); }
|
||||
}
|
||||
|
||||
// 登录失效时:刷新页面抓登录二维码,发群(文字+二维码+补充说明)
|
||||
function notifyLoginExpired() {
|
||||
const label = `${ACCT}(${ACCT === 'hr1' ? 'Chrome·合塑账号' : 'Edge·派卡账号'})`;
|
||||
const text = `🚨 当前${label}账号登录已失效,今日筛选中止。扫码可重新登录:\n如今天不需要协助筛选简历,可忽略该二维码`;
|
||||
const qrPath = `/tmp/zhaopin-login-qr-${ACCT}.png`;
|
||||
try {
|
||||
execSync(`node ${SCRIPTS}/login-qrcode.js ${PORT} ${qrPath}`,
|
||||
{ cwd: SCRIPTS, timeout: 90000, stdio: ['pipe', 'pipe', 'pipe'] });
|
||||
if (fs.existsSync(qrPath) && fs.statSync(qrPath).size > 1000) {
|
||||
sendGroupImage(text, qrPath);
|
||||
return;
|
||||
}
|
||||
log('二维码截图异常(文件过小或不存在),降级为纯文字');
|
||||
} catch (e) { log(`二维码获取失败: ${String(e.message).slice(0, 100)},降级为纯文字`); }
|
||||
send(GROUP, `🚨 当前${label}账号登录已失效,今日筛选中止,请在任务机重新登录智联`);
|
||||
}
|
||||
|
||||
function writeState(status, chatLeft) {
|
||||
fs.writeFileSync(path.join(STATE_DIR, `state-${ACCT}.json`),
|
||||
JSON.stringify({ date: today(), status, chatLeft: chatLeft ?? null, endedAt: new Date().toISOString() }));
|
||||
@@ -159,9 +186,9 @@ function statusText(s) {
|
||||
maybeSendReport('kicked_out', lastChatLeft);
|
||||
break;
|
||||
}
|
||||
// 登录失效 → 群告警,结束
|
||||
// 登录失效 → 群告警(带登录二维码),结束
|
||||
if (/登录已失效|passport\.zhaopin\.com/.test(out)) {
|
||||
send(GROUP, `🚨 ${ACCT}(${ACCT === 'hr1' ? 'Chrome·合塑账号' : 'Edge·派卡账号'})智联登录态已失效,今日筛选中止,请在任务机重新登录智联`);
|
||||
notifyLoginExpired();
|
||||
maybeSendReport('login_expired', lastChatLeft);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* 登录二维码获取器 v1.0(2026-08-27)
|
||||
* 用法:node login-qrcode.js <port> <输出png路径>
|
||||
*
|
||||
* 流程:连CDP → 找登录页tab(没有则刷新推荐页触发跳转)→ 截取二维码区域的图片
|
||||
* 智联登录页二维码是 canvas 或 img 动态渲染,直接整页截图最稳(剪裁左半部分登录卡片区)。
|
||||
*/
|
||||
const path = require('path');
|
||||
function tryRequire(names) {
|
||||
for (const n of names) { try { return require(n); } catch (_) {} }
|
||||
throw new Error('无法加载 playwright-core');
|
||||
}
|
||||
const { chromium } = tryRequire([process.env.PWCORE_PATH, 'playwright-core'].filter(Boolean));
|
||||
|
||||
const PORT = process.argv[2] || '9222';
|
||||
const OUT = process.argv[3] || `/tmp/zhaopin-login-qr-${PORT}.png`;
|
||||
|
||||
(async () => {
|
||||
const b = await chromium.connectOverCDP(`http://127.0.0.1:${PORT}`);
|
||||
let p = b.contexts()[0]?.pages().find(x => /passport\.zhaopin\.com/.test(x.url()));
|
||||
if (!p) {
|
||||
// 找推荐页tab刷新,触发跳转到登录页
|
||||
p = b.contexts()[0]?.pages().find(x => /rd\d?\.zhaopin\.com/.test(x.url())) || b.contexts()[0]?.pages()[0];
|
||||
if (!p) { console.error('NO_PAGE'); process.exit(1); }
|
||||
await p.reload({ waitUntil: 'domcontentloaded', timeout: 60000 }).catch(() => {});
|
||||
await new Promise(r => setTimeout(r, 4000));
|
||||
// 刷新后可能跳到登录页
|
||||
if (!/passport\.zhaopin\.com/.test(p.url())) {
|
||||
await p.goto('https://passport.zhaopin.com/org/login', { waitUntil: 'domcontentloaded', timeout: 60000 }).catch(() => {});
|
||||
await new Promise(r => setTimeout(r, 4000));
|
||||
}
|
||||
}
|
||||
console.log('PAGE:', p.url().slice(0, 90));
|
||||
|
||||
// 等二维码出现(canvas 或 img.qr / 二维码容器,多选择器兜底)
|
||||
const qrSel = [
|
||||
'canvas', // 智联登录二维码多为 canvas 绘制
|
||||
'img[src*="qr"]',
|
||||
'.qrcode', '.qr-code', '.login-qr', '[class*="qr" i]',
|
||||
'.zp-qr', '#qr', '[id*="qr" i]',
|
||||
];
|
||||
let el = null;
|
||||
for (let i = 0; i < 10 && !el; i++) {
|
||||
for (const s of qrSel) {
|
||||
el = await p.$(s).catch(() => null);
|
||||
if (el) {
|
||||
// 校验尺寸:太小的 canvas 可能是图标
|
||||
const box = await el.boundingBox().catch(() => null);
|
||||
if (!box || box.width < 100) { el = null; continue; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!el) await new Promise(r => setTimeout(r, 1000));
|
||||
}
|
||||
|
||||
let shotPath = OUT;
|
||||
if (el) {
|
||||
await el.screenshot({ path: OUT }).catch(async () => { await p.screenshot({ path: OUT }); });
|
||||
console.log('QR_ELEMENT_SHOT');
|
||||
} else {
|
||||
// 兜底:整页截图(登录页通常是全屏二维码布局)
|
||||
await p.screenshot({ path: OUT });
|
||||
console.log('FULLPAGE_SHOT');
|
||||
}
|
||||
console.log('SAVED:', OUT);
|
||||
process.exit(0);
|
||||
})().catch(e => { console.error('ERR:', String(e).slice(0, 150)); process.exit(1); });
|
||||
Reference in New Issue
Block a user