- 硬性预筛门槛: 外贸经验必须(仅工作经历匹配), 培养类拦截, 毕业2020-2026, 年龄<=35 - 七维评分+动态阈值+打招呼纪律 - Hermes每日自动化: daily-runner(09:30-18:00)/daily-report/enforce-cutoff/stop-tasks - v10.4: 每累计200人自动刷新页面 - 修正: CDP端口9222(反向隧道), 通知只发私聊(防串台), hr2任务禁用 - WSL端: cdp-tunnel.sh 浏览器工人守护
9.7 KiB
Executable File
双账号筛选 — Chrome + Edge 方案 (v0.2 已实施)
背景
两个智联招聘账号同时筛选简历,扩大覆盖面和打招呼配额。
方案选型
| 对比项 | 双 Chrome 实例 | Chrome + Edge |
|---|---|---|
| profile 隔离 | 手动 robocopy 一份 profile | 天然隔离,各用各的 |
| 登录互踢风险 | 同浏览器同协议,有风险 | 不同浏览器,cookie 完全隔离,不会互踢 |
| 启动方式 | 要记哪个是哪个 | 桌面图标一目了然 |
| CDP 连接 | playwright connectOverCDP | 完全相同,脚本零改动 |
| 脚本改动 | 零差异 | 零差异 |
结论:Chrome + Edge 方案更优,已采用。
架构
┌──────────────────────────────────────────────────────────┐
│ Linux (Hermes) │
│ │
│ batch-runner (ACCOUNT=hr1) ─CDP_PORT=9223──→ SSH 9223→9222 │
│ batch-runner (ACCOUNT=hr2) ─CDP_PORT=9225──→ SSH 9225→9224 │
│ │
│ recruitment.db (candidates.account 区分来源) │
└──────────────────────────────────────────────────────────┘
│ │
SSH 隧道 9223→9222 SSH 隧道 9225→9224
│ │
┌────────┴──────────┐ ┌────────┴──────────┐
│ Windows 桌面 │ │ Windows 桌面 │
│ Chrome (hr1) │ │ Edge (hr2) │
│ CDP :9222 │ │ CDP :9224 │
│ user-data-dir: │ │ user-data-dir: │
│ C:\temp\ │ │ C:\temp\ │
│ chrome-debug │ │ edge-debug │
└───────────────────┘ └───────────────────┘
端口映射
| 账号 | 浏览器 | Windows CDP | Linux 本地 | SSH 隧道 |
|---|---|---|---|---|
| hr1 | Chrome | 9222 | 9223 | sshpass -p 'xxx' ssh -fN -p 7022 -L 9223:127.0.0.1:9222 sshadmin@8.152.213.143 |
| hr2 | Edge | 9224 | 9225 | sshpass -p 'xxx' ssh -fN -p 7022 -L 9225:127.0.0.1:9224 sshadmin@8.152.213.143 |
Edge 配置
安装路径(已确认)
C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
user-data-dir
C:\temp\edge-debug
首次使用无需从默认 profile 复制,Edge 会在该目录创建新 profile。手动登录第二个智联账号后,登录态自动保存在此目录。
桌面快捷方式(已创建 ✅)
桌面路径:C:\Users\sshadmin.WIN-3NKO8I5R9IJ\Desktop\Edge Debug Mode.lnk
创建方法(通过 scp + cscript):
- 本地写 VBS 脚本到
/tmp/mksc.vbs scp /tmp/mksc.vbs sshadmin@8.152.213.143:\"C:/temp/mksc.vbs\"sshpass -p 'xxx' ssh -p 7022 sshadmin@8.152.213.143 "cscript //nologo C:\\temp\\mksc.vbs"
⚠️ 桌面实际路径是
C:\Users\sshadmin.WIN-3NKO8I5R9IJ\Desktop(非Administrator),通过ws.SpecialFolders("Desktop")自动获取正确路径。
⚠️ CDP 启动方式
SSH 会话内直接启动 Edge → CDP 端口不可达(Windows Session 隔离)。
解决方案:schtasks 计划任务
# 注册(只需一次)
schtasks /Create /IT /RU Administrator /TN LaunchEdgeDebug /TR "\"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe\" --remote-debugging-port=9224 --user-data-dir=C:\temp\edge-debug" /SC ONLOGON /RL HIGHEST
# 每次启动
schtasks /Run /TN LaunchEdgeDebug
/IT = Interactive,在交互式桌面 session 中运行。详见 windows-remote-scraping.md。
数据库改造(已完成 ✅)
ALTER TABLE candidates ADD COLUMN account TEXT DEFAULT 'hr1';
ALTER TABLE greet_log ADD COLUMN account TEXT DEFAULT 'hr1';
CREATE INDEX idx_cand_account ON candidates(account);
现有 2817 条 hr1 数据自动标记 hr1。脚本通过 ACCOUNT 环境变量写入该字段,查询时按 account 过滤。
脚本改造(已完成 ✅)
zhaopin-scrape.js v9.2
改动点:
const ACCOUNT = process.env.ACCOUNT || 'hr1'— 文件顶部- CREATE TABLE 加
account TEXT NOT NULL DEFAULT 'hr1' upsertCandidate()— INSERT 加 account 列和参数logGreet()— INSERT 加 account 列和参数getExistingFingerprints()—WHERE account = ?过滤- 启动快速跳过指纹加载 —
WHERE account = ?过滤
batch-runner.js v2 (多账号版)
改动点:
ACCOUNT/CDP_PORT/TARGET_CITY均从环境变量读取(默认 hr1/9223/郑州)runBatch()传ACCOUNT=xxx给子进程generateBatchReport()— 按 account 过滤generateFinalReport()— 所有 13 处 SQL 加WHERE account = ?getDbCount()— 按 account 过滤- 汇报标题带
[hr1]/[hr2]标识
运行方式
# hr1(Chrome)
ACCOUNT=hr1 CDP_PORT=9223 node zhaopin-scrape.js 50
ACCOUNT=hr1 CDP_PORT=9223 nohup node batch-runner.js > /tmp/batch-runner-hr1.log 2>&1 &
# hr2(Edge)
ACCOUNT=hr2 CDP_PORT=9225 node zhaopin-scrape.js 50
ACCOUNT=hr2 CDP_PORT=9225 nohup node batch-runner.js > /tmp/batch-runner-hr2.log 2>&1 &
Cron 定时任务(已创建 ✅)
| 任务 | 时间 | 账号 | 说明 |
|---|---|---|---|
| 工作日简历筛选 hr1 | 周一至周五 09:50 | hr1/Chrome/9223 | 原 cron 更新,加 ACCOUNT=hr1 |
| 工作日简历筛选 hr2 | 周一至周五 09:55 | hr2/Edge/9225 | 新建,错开 5 分钟避免 DB 锁争用 |
两个任务错开 5 分钟,避免同时启动时的数据库竞争。各自独立汇报到飞书群。
汇报规则
两个账号各自独立汇报,标题带 [hr1]/[hr2] 标识。recruitment-report 查询时按 account 过滤。如需汇总两个账号,去掉 account 过滤条件。
SSH 隧道保活配置(2026-06-01 修复)⚠️ 关键
SSH 隧道频繁断连的根因:客户端和服务端都没有心跳保活。空闲连接被网络/NAT 丢弃后,batch-runner 的 getChatCount() 读到 null,误判为"聊天耗尽"并发群汇报。
客户端保活(Linux ~/.ssh/config):
Host windows-hr
HostName 8.152.213.143
Port 7022
User sshadmin
ServerAliveInterval 15
ServerAliveCountMax 3
TCPKeepAlive yes
ExitOnForwardFailure yes
StrictHostKeyChecking no
服务端保活(Windows C:\ProgramData\ssh\sshd_config):
TCPKeepAlive yes
ClientAliveInterval 30
ClientAliveCountMax 3
修改后需重启 sshd:net stop sshd && net start sshd
两端必须同时配置,仅客户端保活在 Windows OpenSSH 上不可靠。
建隧道命令
# 外网连接(通过内网穿透),需 sshpass 密码认证
sshpass -p 'xxx' ssh -fN -p 7022 -L 9223:127.0.0.1:9222 sshadmin@8.152.213.143
sshpass -p 'xxx' ssh -fN -p 7022 -L 9225:127.0.0.1:9224 sshadmin@8.152.213.143
验证隧道
ss -tlnp | grep -E "9223|9225" # 确认端口监听
curl -s http://127.0.0.1:9223/json/version | head -1 # 确认 CDP 可达
curl -s http://127.0.0.1:9225/json/version | head -1
隧道守护脚本(自动重连)
心跳保活只能降低断连概率,无法 100% 防止。ssh-tunnel-watchdog.sh 作为兜底,每 10 秒检测端口,断了自动重建:
# 启动(与 batch-runner 同时运行)
nohup /home/kt/scripts/ssh-tunnel-watchdog.sh > /tmp/ssh-tunnel-watchdog.log 2>&1 &
脚本路径:/home/kt/scripts/ssh-tunnel-watchdog.sh
监控端口:9223(hr1)、9225(hr2)
日志:/tmp/ssh-tunnel-watchdog.log(仅断连重连时有输出)
batch-runner.js 聊天耗尽验证机制(2026-06-01 新增)
batch-runner.js 现在内置三层防护,防止误判"聊天耗尽":
1. getChatCount() 区分 CDP 状态
- 返回数字:正常读取到聊天次数
- 返回
null:CDP 可达但页面读取失败(弹窗遮挡等) - 返回
'cdp_down':CDP 端口不通(隧道断开/浏览器关闭) - 通过
net.createConnection先探测端口,5秒超时
2. verifyChatExhausted(reason) 二次确认
所有 5 个判定点(启动、主循环、子进程 chat_empty、批次后检查×2)都调用此函数:
- CDP 不通 → 等待 30 秒重试,连续 3 次 CDP 不通 → 判定"连接异常"(不发最终汇报)
- 读到 0 → 连续 3 次确认后才判定真正耗尽
- 读到 >0 → 判定误判,返回剩余次数继续运行
3. stopReason 控制最终汇报
chat_empty:聊天真正耗尽 → ✅ 发最终汇报cdp_down:连接异常 → ❌ 不发汇报,只发"CDP 连接断开"错误通知normal:正常结束 → 不发汇报
日常启动流程
- Windows 桌面:双击「Chrome Debug」→ 打开智联推荐页(hr1)
- Windows 桌面:双击「Edge Debug Mode」→ 打开智联推荐页(hr2)
- Linux:确认两条 SSH 隧道都通(
ss -tlnp | grep -E "9223|9225"+curl http://127.0.0.1:9223/json/version) - Linux:启动隧道守护(
nohup /home/kt/scripts/ssh-tunnel-watchdog.sh > /tmp/ssh-tunnel-watchdog.log 2>&1 &) - Linux:两个 batch-runner 并行启动(或等 cron 自动启动)
已知问题
SSH 隧道不稳定(2026-06-01 已修复:双向心跳保活)CDP 连接失败与聊天耗尽共用退出路径(2026-06-01 已修复:verifyChatExhausted + stopReason)