下载地址
https://www.zhengdianxue.com/wp-content/uploads/skills/koseninfo--yupao-resume-downloader.zip将提示词发送给你的 AI 安装该 skills
请根据 https://skillhub.cn/install/skillhub.md,安装 @koseninfo/yupao-resume-downloader。第一次用户手工登录,自动保存cookie,第二次自动登录,登录之后下载候选人提供的简历到本地,没有提供简历的自动发信息索取简历,下载到本地后按岗位和日期自动归档简历;
阅读全文 (展开查看完整说明)
概述
鱼泡网简历自动下载器(手动登录 + Cookie 复用 + 按岗位/日期两级归档 + 纯原生 CDP 下载)
核心架构(当前版本要点)
- 登录机制(默认):
Cookie 持久化复用 + 首次手动登录兜底。- 首次运行在 Edge 窗口内由用户手动登录一次;登录成功后脚本通过 CDP
Network.getCookies把 yupao.com 的认证 Cookie 存入~/.yupao_downloader/cookies.json。 - 之后所有运行:本地有有效 Cookie → 注入浏览器直接登录(免短信、免手动);Cookie 失效/缺失 → 打开登录页提示用户在 Edge 内手动登录一次,登录后重新保存 Cookie。
- 不依赖任何手机号、短信验证码、webhook 中继或手机端改动。
- 首次运行在 Edge 窗口内由用户手动登录一次;登录成功后脚本通过 CDP
- 下载机制:点「附件简历」打开 PDF.js 预览弹窗(下载按钮在浏览器 chrome 层、DOM 不可见)。真实 PDF 字节从 CDN 直链(
stat102.cdqlkj.cn/...pdf?auth_key=...,带签名、无需登录 Cookie)加载 → 用原生 CDPNetwork域捕获该直链 → Python 直接拉取落盘(校验%PDF头)。GET_RESUME_FILENAME_JS从激活会话项提取原名,_close_preview_if_open()先关残留弹窗避免误捕获上一位候选人。 - 运行模式:
- 首次(全量):下载所有时间/岗位简历,按
{download_dir}/{岗位}/{YYYY-MM-DD}/两级归档(岗位取候选人职位文本,无法识别归入未分类;日期取下载当日,格式2026-07-29);无简历者发 IM 索取消息(3 天冷却);首跑后标记processed.json.full_sweep_done。 - 后续(增量):仅处理当天有沟通的候选人(
CANDIDATE_JS的isToday),已下载去重跳过。 --full-sweep强制全量;_reorganize_existing()首跑前把根目录已有简历按姓名→岗位、再按文件修改日期移入{岗位}/{日期}/子目录。
- 首次(全量):下载所有时间/岗位简历,按
- 执行流:Phase 0 环境自检(自动配置)→ Phase 1 配置检查 → Phase 2 启动 Edge + 登录(含 Cookie 复用 / 首次手动登录)→ Phase 3 原生 CDP 连接下载 → Phase 4 展示结果(详见下文)。
WorkBuddy 对话层执行流程
⚠️ 严格执行顺序:必须按 Phase 0 → 1 → 2 → 3 → 4 顺序执行,不能跳过任何步骤。
📋 配置收集用弹窗:存储目录通过
setup_wizard.py --pick-dir弹系统文件夹选择对话框让用户指定(首次运行必须;后续复用已保存目录)。本技能已无手机号/短信配置,无需弹窗收集手机号或短信转发。
Phase 0: 环境自检与自动配置(用户下载安装后首次运行必做)
目的:确保用户本机环境满足运行要求;不满足的项目自动配置(如自动安装 aiohttp 依赖),无法自动处理的(如缺少 Edge 浏览器)明确提示用户手动完成。每次新用户首次运行前执行一次即可(也可在运行异常时重跑排查环境)。
Step 0: 运行环境自检脚本
cd <skill_dir>/scripts && python env_check.py使用 Python 运行脚本:优先用 WorkBuddy 管理的 Python 虚拟环境(路径形如
<用户主目录>/.workbuddy/binaries/python/envs/default/Scripts/python.exe);也可使用系统 Python 3.10+。
解析 JSON 输出,关注 ok 与 checks 字段:
{
"ok": true, // 是否全部满足
"auto_fixed": 1, // 自动修复了几项
"checks": [ // 逐项明细
{ "name": "Python 版本", "ok": true, "detail": "当前 3.13.x,需要 >= 3.10" },
{ "name": "依赖 aiohttp", "ok": true, "detail": "已安装 / 未安装 → 已自动 pip install" },
{ "name": "Edge 浏览器", "ok": true, "detail": "已找到 msedge.exe / 未找到(需手动安装)" },
{ "name": "系统平台", "ok": true, "detail": "Windows(推荐)" },
{ "name": "运行时数据目录","ok": true, "detail": "就绪: ~/.yupao_downloader(自动创建)" }
]
}检查项与自动配置行为:
| 检查项 | 不满足时的处理 |
|---|---|
| Python 版本(>= 3.10) | 无法自动升级 → 提示安装 Python 3.10+ |
| aiohttp 依赖 | 自动 pip install aiohttp(CDP 通信必需) |
| Edge 浏览器 | 无法自动安装 → 提示安装 Microsoft Edge(CDP 自动化目标) |
| 系统平台 | 非 Windows 给出警告(Edge 路径需自行适配),不阻断 |
运行时数据目录 ~/.yupao_downloader | 自动创建并验证可写 |
若
ok == false:查看失败项的fix_hint引导用户处理;可重跑python env_check.py --no-fix仅检查不自动安装。只有ok == true(或失败项仅为非阻断项)后才进入 Phase 1。
Phase 1: 配置检查与目录选择
Step 1: 检查现有配置
cd <skill_dir>/scripts && python setup_wizard.py --check使用 Python 运行脚本:优先用 WorkBuddy 管理的 Python 虚拟环境(路径形如
<用户主目录>/.workbuddy/binaries/python/envs/default/Scripts/python.exe);也可使用系统 Python 3.10+。首次运行脚本会自动pip install所需依赖(aiohttp)。
解析 JSON 输出,关注 first_run_completed、download_dir_configured 字段。
Step 2: 首次运行 —— 用系统对话框指定简历存储目录(必须)
首次运行还需让用户选择简历保存位置——通过系统文件夹选择对话框(原生 GUI,不是文本输入):
cd <skill_dir>/scripts && python setup_wizard.py --pick-dir⚠️ 该命令会弹出系统文件夹选择窗口,必须在能显示 GUI 的环境下运行(即在用户本机、非纯无头沙箱中执行;若 WorkBuddy 的 Bash 默认在沙箱内运行,需用
dangerouslyDisableSandbox: true或在用户桌面终端执行),否则对话框无法显示、会回退到默认目录。用户选好目录后,路径自动写入
~/.yupao_downloader/config.json的download_dir;后续运行读该值,不再弹窗。也可在后续任意时刻重跑--pick-dir更改目录。
若
--pick-dir不可用/用户取消,主运行脚本(yupao_cdp.py)在首次运行(未配置 download_dir)时也会自动弹出同一系统对话框作为兜底,选完继续;仍失败则回退到默认~/Downloads/鱼泡简历。
运行结束不自动打开目录(硬性):下载阶段结束后只关闭浏览器,不得用系统文件管理器(
os.startfile/open/xdg-open)弹出归档目录。归档目录的完整路径写在统计报告里,由对话层呈现,用户自行前往查看。
Step 3: 标记为手动登录模式(默认)
本技能只支持「手动登录 + Cookie 复用」一种登录方式,无需任何参数;运行以下命令即完成配置(仅标记首次运行完成):
cd <skill_dir>/scripts && python setup_wizard.py输出 {"mode":"manual", ...} 即配置完成。后续运行配置已存在则跳过本步,直接自动化。
配置已自动保存到 ~/.yupao_downloader/config.json。
Phase 2: 启动 Edge + 登录(Cookie 复用 / 首次手动登录)
Step 4: 启动 Edge CDP 调试模式
先检查 Edge 是否已以调试模式运行:
curl -s http://127.0.0.1:9222/json/version如果未运行,启动 Edge(环境检查阶段只打开空白页,不访问鱼泡;鱼泡页面由脚本在登录阶段按需打开):
taskkill /F /IM msedge.exe 2>nul
start "" "C:Program Files (x86)MicrosoftEdgeApplicationmsedge.exe" --remote-debugging-port=9222 --no-first-run --no-default-browser-check --no-restore-session-state --disable-session-crashed-bubble --user-data-dir="%USERPROFILE%.yupao_downloaderedge_profile" "about:blank"如果第一路径不存在,尝试:
start "" "C:Program FilesMicrosoftEdgeApplicationmsedge.exe" --remote-debugging-port=9222 --no-first-run --no-default-browser-check --no-restore-session-state --disable-session-crashed-bubble --user-data-dir="%USERPROFILE%.yupao_downloaderedge_profile" "about:blank"Step 5: 运行登录 + 下载
cd <skill_dir>/scripts && python yupao_cdp.py --non-interactive注意:脚本启动时自动检测并安装
aiohttp(CDP 通信依赖)。如果使用 WorkBuddy 管理的 Python,需通过 venv 运行:
python yupao_cdp.py --non-interactive(使用 WorkBuddy 管理的 Python 虚拟环境,或系统 Python 3.10+;依赖自动安装)
脚本执行流程:
- 检查 CDP 端口(无调试 Edge 则自动启动,仅打开空白页;进入登录阶段后才按需打开鱼泡页面)
- 登录阶段(Cookie 优先 + 手动兜底):
- 路径0 已登录:profile 自带有效会话(URL 在 /web/im 且
is_truly_logged_in()通过)→ 直接继续 - 路径1 Cookie 直接登录(默认首选):本地
~/.yupao_downloader/cookies.json存在 →Network.setCookies注入浏览器 → 跳 /web/im → 校验通过即登录成功,免短信、免手动 - 路径2 手动登录兜底:无 Cookie / Cookie 失效 → 打开登录页,在 stdout 打印登录引导(含说明:Cookie 不过期则以后自动下载到指定目录,无需再手动);用户直接在已打开的 Edge 窗口内登录,成功后脚本持久化 Cookie,下次运行自动走路径1
- 路径0 已登录:profile 自带有效会话(URL 在 /web/im 且
- 下载阶段(登录成功后自动执行):原生 CDP 连接(RawCDPClient) → 扫描候选人 → 下载简历 / 发送消息 → 报告(全程不依赖 Playwright)
🍪 Cookie 机制:首次手动登录成功后,脚本通过
Network.getCookies把 yupao.com 的认证 Cookie 存入cookies.json;后续运行在启动阶段注入,实现「配置一次、长期免登录」。Cookie 过期(通常数天~数周)后首次运行会自动转回路径2:脚本会在 stdout 打印「请在 Edge 窗口中手动登录一次」,并说明——只要 Cookie 不过期,本 skill 之后会自动把简历下载到已配置的目录,无需再次手动登录。用户登录成功后 Cookie 重新保存。
🔕 无弹窗原则(硬性):手动登录不弹任何桌面提示窗(已移除
send_desktop_notification/ WindowsMessageBox/ macOS 通知)。登录引导只走 stdout,由 WorkBuddy 在对话内呈现;用户在已自动打开的 Edge 窗口内直接登录即可。Agent 也不得为「提醒去登录」而额外弹确认卡片——只在对话中一句话说明即可。
🔒 安全门禁(硬性):下载阶段只有在真正登录成功后才允许执行,违反则拒绝下载。
- 主流程:
if not login(): sys.exit(1),登录失败直接退出,绝不进入下载。login()不再仅凭URL == /web/im判断已登录,改用is_truly_logged_in()——依次校验 ①URL 在 /web/im ② 存在认证类 Cookie(token/passport/uid/sid/session/auth…)③ 无「请登录」遮罩 ④ 已渲染候选人列表容器。任一可信信号命中才视为已登录;不确定时宁可强制重新登录,不可误判已登录。download()开头再加一道双保险:若is_truly_logged_in()为 False,打印「安全门禁:未真正登录成功,已拒绝下载简历」并直接返回,不会扫描/下载任何简历。设计目的:防止会话过期、Cookie 残留但已失效等情况下,脚本误以为已登录而去下载(可能拿到空列表或错误数据)。
🏁 任务完成判定(硬性):脚本只有在「登录成功 + 下载阶段真正跑完并生成报告 + 扫描成功 + 无错误」皆满足时,才
exit 0并打印「✅ 任务完成」;否则exit 1并打印「❌ 任务未完成」+ 原因。
- 结果写入
~/.yupao_downloader/completion.json:{"completed", "login_ok", "download_done", "scan_ok", "downloaded", "messaged", "skipped_ok", "errors", "total", "targets", "handled", "nothing_to_do", "report_path"}。- 区分「无事可做」与「真失败」(v29 关键修正):
targets= 本轮实际需处理的候选人数(增量模式过滤后);skipped_ok= 正常跳过(简历此前已下载去重 / 催简历冷却期内 / 已请求待对方确认 / 对应动作被--no-download·--no-message关闭);handled= 下载数 + 发消息数 +skipped_ok,即每个 target 的「明确归宿」。- 判定规则:
targets == 0→ 本轮无需处理任何人,属正常完成;targets > 0→ 需handled > 0才算完成。- ⚠️ 旧逻辑要求「下载数+发消息数 > 0」,会把「候选人此前全部已下载」这类正常增量空跑误判为失败,已修正。
nothing_to_do == true表示任务正常完成但本轮无新增下载/发送,对话层应据此输出「本轮无新简历」而非报错。- 「登录失败」「下载被安全门禁拦截」「扫描失败」等情况仍不会被报告为完成。
🔚 下载完成后的便捷收尾:下载阶段结束后(登录成功、
bot已创建),脚本在退出前通过 CDPBrowser.close关闭整个 Edge 进程(专用自动化 profile,关闭无副作用;失败则兜底taskkill msedge.exe)。不会用系统文件管理器自动打开归档目录(用户偏好:不弹窗、不逐份展示),归档目录完整路径写入统计报告由用户自行前往。
💬 任务完成判定门禁(对话层,硬性):只有
completion.json中completed == true(即 login_ok 且 download_done 同时为真)时,Agent 才允许在对话中输出「✅ 任务完成」并附统计报告;任何completed == false(登录失败、报告未生成、脚本 exit 1)的情况,不得声称完成,而应输出「❌ 任务未完成」并附原因(登录失败 / 报告未生成等),引导用户重试或排查。结论一律在对话正文中给出,不弹对话框、不弹确认卡片。
Phase 3: 展示结果
脚本运行完成后,输出类似:
===============================================================
📊 处理完成!
──────────────────────────────
当前轮次: 12 个候选人
📥 本次下载: 5
💬 本次发送: 6
⏭ 跳过: 1
❌ 出错: 0
──────────────────────────────
历史累计下载: 23 份
历史累计发送: 18 条
📁 简历目录: C:UsersxxxDownloads鱼泡简历
===============================================================向用户摘要展示当前轮次处理了多少候选人、下载/发送/跳过数量、历史累计统计。
📄 只给统计报告,不逐份展示简历(硬性):结束时只在对话中输出一份统计报告(表格或列表:扫描数 / 本次下载 / 跳过 / 出错 / 历史累计 / 归档目录路径)。
- 禁止对下载到的每份简历调用
present_files,也禁止逐份罗列文件卡片。- 需要时最多用一行文字带出候选人姓名清单(如「本次下载:张三、李四、王五」),并给出归档目录的完整路径,让用户自行前往查看。
- 跳过 / 出错的候选人只需汇总说明原因,不必逐条展开细节。
- 也不自动打开归档目录:脚本侧已移除
open_download_folder(),Agent 侧同样不得代为打开文件夹。
⚠️ Phase 3 完成判定门禁:输出报告前,先读
~/.yupao_downloader/completion.json:
completed == true→ 输出「✅ 任务完成」+ 统计报告。其中若nothing_to_do == true,文案应为「✅ 本轮无新简历可下载」并说明原因(候选人此前均已下载 / 冷却期内 / 待对方确认),不得当作失败。completed == false或文件不存在 / 脚本 exit 1 → 不得声称完成;改为输出「❌ 任务未完成」并说明原因(登录失败 / 扫描失败 / 报告未生成)。- 禁止仅凭脚本打印了「✅」字样或日志结尾有内容就判定完成——必须以
completion.json.completed为准。
可用参数
env_check.py(环境自检与自动配置,Phase 0)
| 参数 | 说明 |
|---|---|
| (无参数) | 执行环境自检,不满足自动修复(自动安装 aiohttp、创建数据目录) |
--no-fix | 仅检查并输出报告,不自动安装/修复 |
输出 JSON:
{"ok", "auto_fixed", "checks":[{name, ok, detail, fix_hint?}]}。WorkBuddy 解析后向用户展示检查报告;ok == false时按fix_hint引导处理。
setup_wizard.py(配置向导)
| 参数 | 说明 |
|---|---|
--check | 仅检查当前配置状态(登录模式 / 下载目录),输出 JSON |
--pick-dir | 弹出系统文件夹选择对话框,让用户指定简历存储目录并保存(首次运行使用) |
| (无参数) | 标记为「手动登录 + Cookie 复用」模式(默认) |
输出 JSON 格式,WorkBuddy 解析后用于确认配置状态 / 展示所选目录。
yupao_cdp.py(登录+下载)
| 参数 | 说明 |
|---|---|
--non-interactive | 非交互模式(WorkBuddy 中必须使用;无 Cookie 且手动模式会先提示需交互登录一次) |
--full-sweep | 强制首次全量模式 |
--download-dir DIR | 指定简历下载目录 |
--no-download | 跳过简历下载(仅登录) |
--no-message | 跳过消息发送 |
--no-auto-edge | 不自动管理 Edge(已手动启动时使用) |
注意:配置由
setup_wizard.py管理,yupao_cdp.py只执行登录+下载。本技能不提供--phone/--phone-type/--sms-fallback/--webhook-url等任何与短信、webhook 中继相关的参数。
目录结构
yupao-resume-downloader/
├── SKILL.md # 本文件
├── scripts/
│ ├── yupao_cdp.py # 核心 CDP 自动化脚本(登录:Cookie 复用 + 首次手动;下载:原生 CDP 捕获 PDF 直链)
│ ├── setup_wizard.py # 配置向导(检查配置 / 选择目录 / 标记手动登录模式)
│ ├── config_manager.py # 配置管理(登录模式 / 下载目录 / Cookie / 已处理记录)
│ └── env_check.py # 环境自检与自动配置(Phase 0:检查 Python/依赖/Edge/目录,缺失自动修复)
├── references/
│ └── site_selectors.md # 鱼泡网 CSS 选择器参考
└── assets/
└── config_template.json # 配置模板发布包(
yupao-resume-downloader.zip)仅包含SKILL.md、LICENSE.txt、scripts/yupao_cdp.py、scripts/setup_wizard.py、scripts/config_manager.py、scripts/env_check.py、references/、assets/。所有自动化登录辅助模块(anti_detect.py/drag_solver.py/gap_detector.py/win32_input.py/slider_solver.py/test_e2e.py)及备用入口(yupao_downloader.py/yupao_login_and_download.py/action_recorder.py/action_replayer.py)与短信/webhook 登录文档(references/iphone_shortcut_guide.md)已从仓库彻底移除,不保留任何短信/webhook 登录逻辑。
故障排除
CDP 连接失败
- 确保 Edge 已关闭:
taskkill /F /IM msedge.exe - 重新执行 Step 4 启动 Edge
- 用浏览器访问
http://127.0.0.1:9222/json/version验证
候选人列表为空
- 确保在「沟通」页面(
/web/im),而非「推荐牛人」页面 - 页面结构可能更新 → 更新
CANDIDATE_JS ❌ 候选人扫描失败(CDP 求值未返回列表): 若日志报扫描失败且scan_ok=False,优先排查_build_js对 IIFE 的包裹:CANDIDATE_JS本身已是自调用箭头函数(() => {...})(),_build_js旧逻辑会再把末尾)()截掉再包一层f"{t}()",导致箭头函数缺右括号、Uncaught SyntaxError: Unexpected token '('、求值静默返回None。修复后_build_js对以)()/()结尾的模板原样透传,不再二次包裹。
登录失败 / Cookie 失效
- 登录阶段使用纯 CDP WebSocket 通信,不连接 Playwright。登录按两层降级:① profile 已登录 → ② 注入本地 Cookie(
cookies.json)直接登录 → ③ 浏览器内手动登录一次(默认首次方式)。 - 首次运行 / Cookie 过期:脚本会打开登录页并显式提示「请在 Edge 窗口中手动登录一次」,提示中说明——只要 Cookie 不过期,之后 skill 会自动把简历下载到指定目录,无需再次手动登录。用户在浏览器里自己输入手机号+验证码+拖滑块即可;登录成功后自动保存 Cookie,之后运行无需再手动。
- 如果手动登录也失败:检查 Edge 是否真的在前台、滑块是否拖完、网络是否正常;Cookie 过期只需重新手动登录一次即刷新。
- GeeTest 滑块卡在
freeze_wait状态: 页面刷新即可重置。手动登录时由用户自行完成滑块验证,脚本不干涉。 - "获取验证码" 按钮未找到:手动登录时需先点击「验证码登录/注册」区域切换到短信登录模式,再输入手机号获取验证码。