下载地址
https://www.zhengdianxue.com/wp-content/uploads/skills/koseninfo--zhilian-resume-downloader.zip将提示词发送给你的 AI 安装该 skills
请根据 https://skillhub.cn/install/skillhub.md,安装 @koseninfo/zhilian-resume-downloader。自动从智联招聘聊天(IM)页面下载候选人附件简历,通过 CDP 远程调试操控用户本地 Edge 浏览器
阅读全文 (展开查看完整说明)
概述
智联招聘简历自动下载器 (v4 — 纯 CDP 重构版)
参考 yupao-resume-downloader 的成熟架构整体重构。核心变化:弃用 Playwright,改用纯 WebSocket 的 RawCDPClient 传输层(基于 aiohttp),对 SPA 路由切换天然免疫;引入反检测注入、配置校验向导、真登录安全门禁 + completion.json 完成门禁。
核心能力
- 纯 CDP 传输层:
raw_cdp_client.py基于 aiohttp WebSocket,不依赖 Playwright,导航/路由切换不会丢失页面上下文 - 反检测注入:复用通用
anti_detect.py,屏蔽navigator.webdriver等自动化特征 - 首次运行配置向导:带校验(手机号格式、目录可写性),仅需配置一次
- 首次人工登录 + Cookie 自动复用:首次触发启动智联企业招聘登录页,由用户在浏览器中手动完成登录,登录成功后自动把登录态保存到
cookies.json;后续运行用保存的 Cookie 自动登录,无需人工干预;Cookie 失效时自动回退到「重新人工登录一次」并刷新保存的 Cookie - 验证码接收服务(对齐鱼泡):
code_receiver.py提供两套互补接收方式- 云端中继
CloudCodeReceiver(iPhone 默认主路径):脚本自动创建 webhook.site 中继地址并存入config.json,iPhone 快捷指令把验证码推到该地址,脚本出站轮询读取,无需开放防火墙端口 - 本地 HTTP 接收
CodeReceiver:兜底,脚本在 PC 启动 HTTP 服务(默认端口 18990),iPhone 快捷指令直推http://<PC_IP>:<port>/code?code=XXX(需同一局域网) - 文件轮询兜底:最弱兜底,验证码写入
~/.zhilian_downloader/sms_code.txt,脚本自动续跑
- 云端中继
- Android ADB 自动读取验证码:Android 手机通过 USB 连接,自动读取短信实现全自动登录
- Cookie 自动复用:登录后 Cookie 由 Edge 自动管理,下次免登录
- 双路径下载:推荐页(投递列表)与聊天页(IM 沟通)两条下载链路
- 浏览器下载 + 目录轮询落盘:用
Browser.setDownloadBehavior指定目录,轮询新文件落盘,校验%PDF-魔数 - 安全门禁:仅当真登录成功且下载阶段已执行完毕才写
completion.json标记完成 - 对话框报告(无文件):下载结果仅打印到 WorkBuddy 对话框/终端,不落盘任何 JSON 报告文件
架构(对齐鱼泡下载器)
zhilian-resume-downloader/
├── SKILL.md # 本文件(Skill 执行指引)
├── scripts/
│ ├── zhaopin_cdp.py # 主逻辑(v4 主力,使用 RawCDPClient)
│ ├── raw_cdp_client.py # 纯 aiohttp WebSocket CDP 传输层(移植自鱼泡 RawCDPClient)
│ ├── anti_detect.py # 通用反检测注入 JS(复用鱼泡)
│ ├── config_manager.py # 带校验的明文 JSON 配置管理(含 webhook_url / code_receiver_port)
│ ├── setup_wizard.py # 带校验的配置向导(含验证码接收服务配置)
│ ├── code_receiver.py # 验证码接收服务(云端中继 webhook.site + 本地 HTTP)— 对齐鱼泡
│ └── _legacy/ # 旧版脚本归档(v3 及调试脚本,不再使用)
├── references/
│ └── site_selectors.md # 智联招聘页面选择器参考
└── assets/
└── config_template.json # 配置模板模块职责
| 模块 | 职责 |
|---|---|
raw_cdp_client.py | RawCDPClient:connect / send_command / evaluate / navigate / set_download_dir / wait_for_new_file。纯 WS,SPA 免疫 |
anti_detect.py | ANTI_DETECT_JS:注入屏蔽自动化特征 |
config_manager.py | load_config / save_config / validate_config / is_first_run / get_webhook_url / set_webhook_url / extract_webhook_uuid / CONFIG_DIR |
setup_wizard.py | run_wizard():交互式带校验向导(含 iPhone 云端中继自动创建),返回是否成功 |
code_receiver.py | CodeReceiver(本地 HTTP)/ CloudCodeReceiver(webhook.site 中继)/ get_local_ip / 快捷指令指引文案 |
zhaopin_cdp.py | ZhilianDownloader:登录(填手机号+勾协议+点获取验证码+无滑块)、_wait_for_sms_code 接收服务、is_truly_logged_in 安全门禁、write_completion 完成门禁、main() 编排 |
依赖
仅需 aiohttp(传输层),不再需要 Playwright / chromium:
python -m pip install aiohttp执行总流程
当用户触发本 Skill 时,按以下步骤执行:
┌──────────────────────────────────────────────────────────────────┐
│ Step 1: 首次触发 → 弹出简历存储目录选择框,用户选择后保存配置 │
│ (~/.zhilian_downloader/config.json.download_dir) │
│ · 后续触发(配置已有目录)直接使用,不再弹窗 │
│ ↓ │
│ Step 2: 启动 Edge 调试模式(独立 edge_profile + 端口 9222) │
│ ↓ │
│ Step 3: 登录 │
│ · 首次(无 cookies.json)→ 启动企业招聘登录页,用户在浏览器 │
│ 手动登录;登录成功后自动保存 Cookie(cookies.json) │
│ · 后续(有 cookies.json)→ 用保存 Cookie 自动登录 │
│ · Cookie 失效 → 回退「重新人工登录一次」并刷新 Cookie │
│ ↓ │
│ Step 4: 真登录门禁 → 确认登录成功后才进入下载 │
│ ↓ │
│ Step 5: 双路径下载(按 岗位/日期 分目录)→ 去重 → 无简历自动回复 │
│ → 在 WorkBuddy 对话框报告结果 │
│ ↓ │
│ Step 6: 下载完成后收尾(仅登录成功时) │
│ · 关闭智联浏览器窗口(Browser.close / taskkill) │
│ · 在 WorkBuddy 对话框(终端/日志)报告下载结果 │
│ ↓ │
│ Step 7: 以上全部完成 → 写 completion.json(completed=true) │
└──────────────────────────────────────────────────────────────────┘Step 1: 首次运行检测与配置
1.1 检测是否首次运行
import sys; sys.path.insert(0, '<skill_dir>/scripts')
from config_manager import is_first_run
if is_first_run():
# 进入首次配置1.2 首次运行配置向导
✅ 已移除手机号 / 手机类型的交互收集逻辑(含短信转发配置的确认步骤)。
正常运行不再弹窗询问手机号或手机类型;首次登录所需的手机号直接沿用
config.json中已有的值(首次使用可经
--setup一次性写入)。仅「简历保存目录」通过弹窗/确认卡片选择。
配置内容:
- 简历保存目录:默认
~/Downloads/zhilian_resumes或用户自定义(运行加--ask-dir弹窗选择,或 Agent 用确认卡片选好后以--download-dir传入) - 登录手机号(可选,仅首次):若
config.json无phone,首次登录前由--setup写入一次;正常运行不再收集
Android 用户 → 显示 ADB 配置说明(仅首次登录用,非交互收集):
手机端:
1. 设置 → 关于手机 → 连续点7次「版本号」
2. 设置 → 开发者选项 → 开启「USB调试」
3. USB 连接电脑,手机上点「允许USB调试」
电脑端(二选一):
· 方案A: 运行 scoop install adb
· 方案B: 下载 Platform Tools
https://developer.android.com/tools/releases/platform-tools
验证: 命令行输入 adb devices 看到设备即成功iPhone 用户 → 验证码获取方式(仅首次登录用):
若无 Mac 短信转发:手动在 iPhone 上查看验证码,写入
%USERPROFILE%.zhilian_downloadersms_code.txt
脚本自动轮询读取并继续(不再有短信转发配置的确认弹窗)。然后保存配置(带校验):
import sys; sys.path.insert(0, '<skill_dir>/scripts')
from config_manager import load_config, save_config, validate_config
from setup_wizard import run_wizard
c = load_config()
c['phone'] = 'config.json 中已有的手机号(不交互收集)'
c['download_dir'] = '用户选择的目录'
c['first_run_completed'] = True
errs = validate_config(c)
if errs:
print('配置有误:', errs) # 不应出现
save_config(c)
print('配置已保存')Step 2: 启动 Edge 调试模式
⚠️ 关键点:当前版本 Edge 强制要求
--remote-debugging-port必须配合--user-data-dir,否则浏览器静默退出、端口起不来。脚本内置find_edge_path()+ 独立edge_profile数据目录处理此问题,无需手动指定。
2.1 关闭已有 Edge 进程
taskkill /F /IM msedge.exe 2>nul2.2 以调试模式启动 Edge(独立用户数据目录)
脚本已内置此启动逻辑(--no-auto-edge 时由用户/代理手动启动亦可):
"C:Program Files (x86)MicrosoftEdgeApplicationmsedge.exe" ^
--user-data-dir="%USERPROFILE%.zhilian_downloaderedge_profile" ^
--remote-debugging-port=9222 --no-first-run --no-default-browser-check ^
"https://rd.zhaopin.com"2.3 验证 CDP 端口
curl -s http://localhost:9222/json/version返回含 Browser 字段的 JSON 即就绪。
Step 3: 运行 CDP 自动化脚本
Skill 目录:~/.workbuddy/skills/zhilian-resume-downloader/scripts/
标准运行(使用已有配置 + 自动管理 Edge):
cd <skill_dir>/scripts && python zhaopin_cdp.py已手动启动 Edge 时:
cd <skill_dir>/scripts && python zhaopin_cdp.py --no-auto-edge指定手机类型 / 模式 / 上限:
cd <skill_dir>/scripts && python zhaopin_cdp.py --phone-type iphone --mode chat --max 50强制重新配置:
cd <skill_dir>/scripts && python zhaopin_cdp.py --setup强制全量重新扫描(忽略增量历史,重新覆盖全部候选人):
cd <skill_dir>/scripts && python zhaopin_cdp.py --full可用参数
| 参数 | 说明 |
|---|---|
--setup | 强制运行首次配置向导 |
--phone PHONE | 智联招聘登录手机号 |
--phone-type TYPE | 手机类型:android 或 iphone |
--mode MODE | 下载路径:chat(默认,IM 沟通)或 recommend(投递列表) |
--max N / -m N | 最大下载数量(0=不限) |
--full | 强制全量扫描(忽略 seen_candidates.json 历史,重新处理全部候选人并索要未回复者) |
--no-auto-edge | 不自动管理 Edge(已手动启动时使用) |
--download-dir PATH | 简历保存目录(根目录;实际按 岗位/日期 分子目录) |
--ask-dir | 登录前弹出原生目录选择框,让用户选择简历存放目录 |
--explore | 仅探查聊天页 DOM 结构并写出 chat_explore.json / chat_page.html,不下载 |
登录前目录选择(重要)
下载前必须先确定简历根目录。两种触发方式(二选一):
- 用户弹窗选择(推荐):运行脚本时加
--ask-dir,脚本会弹出原生文件夹选择框,
用户选好后该目录会记住到 config.json,便于下次默认。
- Agent 预选后传入:Agent 通过弹窗/确认卡片让用户选好目录,再以
--download-dir "<用户选择的目录>" 传入。
若既无
--ask-dir也无--download-dir且配置中目录为空,脚本也会自动弹出选择框。
存放规则:按 岗位 / 日期 分目录
简历不会平铺在根目录,而是自动落到子目录:
<根目录>/
└── <岗位名>/ # recommend 模式取岗位标题;chat 模式固定为「聊天沟通」
└── 2026-07-29/ # 当天日期(TODAY_STR)
├── 张三.pdf
├── 李四.pdf
└── ...recommend模式:每个岗位一个子目录,目录下再按日期分层。chat模式:统一落在聊天沟通/日期/下。- 切换岗位/日期时会通过
Browser.setDownloadBehavior动态改下载落盘目录。
去重规则
- 下载前先递归扫描根目录下所有
*.pdf/*.doc/*.docx,按「姓名(忽略_N序号)」
判断是否已下载过;命中则跳过并计入 duplicate。
- 同一候选人若同时出现在多个岗位,也只下载一次。
- 已回复集合(
~/.zhilian_downloader/replied_candidates.json)跨运行持久化,避免对同
一候选人重复发送索要简历消息。
全量 / 增量 下载模式(首次全量,后续增量)
为避免每次运行都重复扫描全部候选人、并向已沟通过的候选人反复索要简历,脚本按「首次全量、后续增量」的语义运行,由 ~/.zhilian_downloader/seen_candidates.json(跨运行持久化的「已见候选人」集合)自动判定:
- 首次运行 /
--full:scan_mode = full。- 处理全部候选人:有附件简历的下载;无附件简历且从未索要过的,自动发送索要消息。
- 本轮见过的所有候选人写入
seen_candidates.json,后续即视为「已见」。
- 后续运行(无
--full且有历史记录):scan_mode = incremental。- 新候选人(不在
seen_candidates.json中):与首次一致——下载附件 + 必要时索要。 - 已见候选人:仅尝试抓取其「迟到 / 新发」的附件简历(点击查看附件简历,有则下载),
- 新候选人(不在
绝不再次发送索要消息(避免重复骚扰)。
- 已见且无新附件可下的候选人计入
incremental_skipped,不重复打开会话、不打扰。
设计要点:索要(自动回复)资格 =
全量模式或新候选人。replied_candidates.json仍作为兜底(已索要过的绝不二次索要)。这样「首次全量」把所有人覆盖一次,此后每次
运行只做增量,不会越跑越像地毯式群发。
--full可强制重新全量扫描(忽略历史已见记录),适合想重新收集时手动触发。- 删除
seen_candidates.json即可让下一次运行重新走「首次全量」。 - 本轮扫描模式(
full/incremental)与new_candidates/incremental_skipped统计
会直接打印在 WorkBuddy 对话框的下载报告中,不再落盘 JSON 报告文件。
聊天页下载机制(实测可用)
聊天页候选人通过 IM 发送的附件简历下载链路(已实测跑通,无需预览 UI / 无需弹窗):
- 用真实鼠标坐标点击会话内的「查看附件简历」按钮
(.im-session-detail .im-attachment-card__button button);普通 JS el.click() 对 Vue 绑定无效,必须用 Input.dispatchMouseEvent 可信事件。
- 点击触发
GET /api/resume/getAttachResumeInfo,响应返回带签名的临时直链
url + fileName + fileType(如 attachment.zhaopin.com/.../downloadFileTemporary?file=...)。
- 直接
urllibGET 该直链(实测无需登录 Cookie 即可拉取,令牌自带签名),
落盘到 聊天沟通/日期/<姓名>.pdf。
⚠️ 并非所有候选人都可下载:只有真正发过附件简历且账号有权限的候选人才有该按钮;
其余候选人会话内只有「要附件简历 / 查看电话」等动作,脚本会对这类候选人自动发送
索要简历消息(受
replied_candidates.json跨运行去重,不重复骚扰)。
无简历候选人自动回复
recommend模式中,若某候选人卡片没有可下载的简历链接(无下载简历/简历
入口),脚本自动通过卡片的「沟通 / 发消息 / 立即沟通」按钮打开 IM,输入并发送一条索要简历的消息(文案见 config.json 的 auto_reply_message,可用 auto_reply_enabled关闭)。
- 发送为 best-effort:任一步失败仅计入
errors,不阻断整体下载流程。 - 已回复的候选人会写入
replied_candidates.json,后续运行不再重复骚扰。 - ⚠️ 该能力依赖智联页面结构(沟通入口 / IM 输入框 / 发送按钮的选择器),若智联改版
需按 _call(CLICK_COMMUNICATE_JS, ...) / FOCUS_IM_INPUT_JS / CLICK_SEND_JS 微调。
Step 4: 真登录安全门禁
重构的核心安全点:绝不在未真实登录的情况下下载任何简历。
ZhilianDownloader.is_logged_in()通过检测页面是否脱离passport.zhaopin.com登录域 + 是否存在企业端会话标识来判定- 仅在
is_logged_in()返回True后才进入下载流程 - 若未登录,脚本进入登录分支(iPhone 等待
sms_code.txt、Android 走 ADB),绝不越权下载
Step 5: completion.json 完成门禁
运行结束写 ~/.zhilian_downloader/completion.json:
{
"completed": true,
"login_ok": true,
"download_done": true,
"downloaded": 12,
"skipped": 8,
"errors": 0,
"updated_at": "2026-07-16 11:50:00"
}completed在 登录成功 + 下载阶段已执行完毕 时为真;脚本随后会执行收尾
(关闭智联窗口 + 工作区域报告结果),以上全部完成才算任务真正完成(对应需求:「以上任务全部完成,才是真正的任务完成」)。
- 不再以「是否新下载到简历」作为完成门槛:增量模式下若本轮无新简历可下(全部已见且无迟到附件),
下载阶段仍视为正常执行完毕,整条任务流程走完即 completed=true,且不会重复骚扰已见候选人。
- 若登录失败(含人工登录超时),
login_ok=false→completed=false,且不在工作区域报告下载结果。 - 用于定时任务判断本轮是否真正跑通。
Step 6: 展示处理结果
脚本运行完成后输出类似:
============================================================
📊 处理完成!
──────────────────────────────
岗位数: 5
候选人总数: 23
📥 下载简历: 12
⏭ 跳过: 8
❌ 出错: 3
📁 保存目录: %USERPROFILE%Downloadszhilian_resumes
============================================================向用户摘要展示:岗位数、候选人数、下载份数、保存位置(报告仅在 WorkBuddy 对话框输出,无文件)。
登录与 Cookie 机制
登录分两条路径,脚本自动判定(见 handle_login / is_truly_logged_in / _manual_login / _auto_login_with_cookies):
- 第 1 次运行(无
cookies.json):脚本启动智联企业招聘登录页,由用户在浏览器中手动完成登录(输入账号密码/扫码等);检测到登录成功后,自动把当前登录态快照保存到~/.zhilian_downloader/cookies.json。 - 第 2 次及以后(有
cookies.json):脚本把保存的 Cookie 写回浏览器并校验is_truly_logged_in();有效则 直接自动登录,全程无需人工干预。 - Cookie 失效 / 过期:自动登录校验失败(
is_truly_logged_in()返回 False),脚本自动回退到「重新人工登录一次」——再次弹出登录页等待用户手动登录,登录成功后刷新cookies.json。
设计要点:登录态的「真相来源」是
cookies.json(由config_manager.save_cookies/load_cookies管理);Edge 的
edge_profile用户数据目录作为补充持久化,二者任一有效即可自动登录。脚本绝不在未真正登录的情况下下载任何简历(见下方安全门禁)。
登录等待人工的超时默认为 5 分钟(_manual_login 中 time.time() + 300),超时未完成则判定登录失败、本轮任务终止。
定时自动化
创建 WorkBuddy automation:
- 调度类型:recurring
- RRULE:
FREQ=DAILY;BYHOUR=9;BYMINUTE=0(每天 09:00) - Prompt:
运行 zhilian-resume-downloader 下载智联招聘新简历 - 工作目录:
<skill_dir>/scripts/
注意:定时任务需要 Android + ADB 才能全自动。iPhone 定时运行时需确保
sms_code.txt能被及时写入。
故障排除
CDP 连接失败 (localhost:9222 不可达)
taskkill /F /IM msedge.exe关闭所有 Edge- 确保启动参数含
--user-data-dir(脚本已处理) - 重新启动 Edge 调试模式,访问
http://localhost:9222/json/version验证
登录失败
- 检查手机号是否正确
- iPhone:确认
sms_code.txt写入的是最新验证码 - Android:确认
adb devices可见设备 - Cookie 冲突:清除浏览器 Cookie 后重试
岗位列表为空
- 确认已真实登录企业端
- 确认有在招岗位
- 智联更新页面结构 → 更新
zhaopin_cdp.py中的选择器(参考references/site_selectors.md)
缺少 aiohttp
python -m pip install aiohttpv4 已移除 Playwright 依赖,纯 CDP 传输层更轻量、对 SPA 路由切换更稳定。