WorkBuddy 每日积分自动领取(通用引导版)
Overview
本 skill 用 Python + pyautogui + OpenCV 模板匹配,自动化操作 WorkBuddy 桌面客户端里固定位置、固定样式的 UI 元素,典型用途是每日积分/签到/福利的一键领取。与"写死坐标"的脚本不同,本 skill 采用引导式校准:第一次运行时由用户在自己客户端上截图裁剪出各步骤模板,之后脚本靠模板匹配定位点击,对分辨率/窗口大小变化更鲁棒。
核心价值不在"一键脚本"(GUI 自动化无法真正开箱即用),而在两样可复用的资产:
1. scripts/capture_templates.py —— 引导用户在自己的客户端上生成专属模板,避免拿别人的截图去匹配自己的界面。
2. 下面这份踩坑清单 —— 全部来自真实生产环境验证,覆盖模板分辨率、误匹配、锁屏、OCR 读数等高频失败点,照做可省下数天调试。
When to Use
- 用户想自动领取 WorkBuddy 每日积分 / 签到 / Buddy 加油站福利
- 用户要在 WorkBuddy 客户端内固定 UI 上设置定时点击序列
- 工作流包含稳定可视元素(按钮、图标、文本区域),可裁剪为模板
How It Differs From a One-off Script
直接移植他人脚本几乎必然失败:每个人的客户端 UI 渲染、窗口尺寸、屏幕分辨率、语言包都不同。本 skill 强制首次校准——用户用自己的客户端生成 templates/,脚本只依赖这些用户专属模板。这是上传市场的合规形态:别人装后能"引导式"为自己搭建,而非拿一个必然在自己的环境失效的硬编码脚本。
Directory Layout
workbuddy-daily-credits/
├── SKILL.md
├── scripts/
│ ├── capture_templates.py # 引导校准:截图裁剪各步骤模板
│ └── claim_credits.py # 通用领取主脚本(读 config.json + templates/)
├── references/
│ └── troubleshooting.md # 踩坑全集(详细版)
└── README.md # 市场说明 / 安装与首次校准步骤
Workflow
1. 安装依赖
python -m pip install pyautogui Pillow opencv-python pygetwindow
# 可选:读取领取后积分余额做对账
python -m pip install winocr # Windows 自带 OCR,仅 zh-Hans-CN
Python 解释器建议用 WorkBuddy 自带的隔离环境(如 C:\Users\<you>\.workbuddy\binaries\python\envs\default\Scripts\python.exe),避免污染系统环境。
2. 首次校准(关键)
- 打开 WorkBuddy 桌面客户端,手动走一遍领取流程,停在"待领取"界面。
- 运行
python scripts/capture_templates.py。 - 脚本对每个待捕捉元素弹出全屏截图,用户拖拽框选该元素(如左下角头像、福利入口、领取按钮、已领取标识)。
- 脚本按原图坐标裁剪、转 RGB、存入
templates/。 - 校准后务必跑
python scripts/claim_credits.py --test只定位不点击,确认每个模板在当前界面能被命中;再用--dry-run验证点击坐标正确。
3. 配置 config.json
claim_credits.py 读取同目录 config.json:
{
"window_title_hint": "WorkBuddy",
"templates_dir": "templates",
"state_file": "claim_state.json",
"notify_cmd": "",
"confidence": 0.85
}
window_title_hint:pygetwindow 模糊匹配的标题片段(大小写不敏感,注意它会匹配到含该词的任意窗口,见踩坑)。notify_cmd:领取成功/失败后的通知命令,留空则仅打印;可填飞书/系统通知脚本路径。
4. 运行领取
python scripts/claim_credits.py
脚本流程:激活窗口 → 截图 → 依次模板匹配"入口→领取按钮"→ 点击 → 检测"已领取"标识短路 → 写 claim_state.json(last_date)→ 调用 notify_cmd。含"今日已领"短路:若 state 已是今天,秒退零 UI 操作。
5. 设为定时任务
用 automation_update(scheduleType=recurring)在客户端常开但无人使用时触发。建议主任务 + 一个较晚的兜底备份(兜底命中"今日已领"短路,不重复领取)。
Key Implementation Notes
- 模板必须从
pyautogui.screenshot()的原生分辨率截图裁剪,绝不用聊天里转发的缩放图。 - 模板存 RGB(非 RGBA),避免 cv2/imread 读图异常。
- 用
locateCenterOnScreen/locateOnScreen+confidence=0.85,预加载模板为 PIL Image 对象规避中文路径问题。 - 脚本开头激活窗口、结尾
Esc复位 UI、点击空白区清理,避免残留面板干扰下次匹配。 - 失败时在
debug/落截图,便于回查。
🚨 CRITICAL: Template Resolution Pitfall
locateOnScreen 不会缩放模板去适配不同分辨率。模板 260×90、实际元素 750×255 → 永远静默匹配失败。
典型失败链:用户把 673×378 的截图粘进聊天 → 你从那里裁出 260×90 模板 → 实际屏 1920×1080、真实元素约 750×260 → 在 1920×1080 截图里找不到 260×90 的模板 → 报"未找到"却不说原因。
解法:始终从原生分辨率 debug 截图重新裁模板。首次失败先看 debug/*.png(那是 pyautogui.screenshot() 的原生输出),从原生图裁同样的元素替换模板,再测。
Common Pitfalls(高频失败点)
- 🚨 模板分辨率不匹配(最常见失败因,见上)。
- 🚨 模板过宽导致误匹配:模板含过多通用内容(如到处出现的文字标签),高置信度下仍会返回成百上千个假候选,按位置排序的第一命中常是 PowerShell/终端里的假阳性。修正:只裁唯一视觉签名(图标 + 最小上下文),不要裁整行 UI。
- 🚨 匹配分 vs 置信度阈值:真实目标匹配分可能低于配置的
confidence(渲染/尺寸微差)。用不同 conf 对同一张真实截图测试模板验证。 - 🚨 不要用子元素包围盒推算点击坐标:例如用"100"文字的匹配框去算底部"领取"按钮位置会打偏。为每个可点击目标单独建模板,用
locateCenterOnScreen定位它。 - 🚨 外部库模糊匹配:
pygetwindow.getWindowsWithTitle是大小写不敏感子串匹配。workbuddy_credits这类文件夹窗口标题含 "workbuddy" 也会命中。始终对候选按标题二次过滤(文件夹类标题含下划线且无空格)。 - 🚨 numpy 负索引 + region:
pyscreeze._locateAll_opencv做haystack[y:y+h, x:x+w]。若 x/y 为负(最大化窗口返回left=-8,来自 DWM 阴影偏移),numpy 把 -8 当"从末尾",把 haystack 缩成几像素并抛 "needle exceeds haystack"。修正:在用作 region 前把窗口 rect 夹到0<=x<=screen_w, 0<=y<=screen_h。 - 🚨 stale
_active_win_rect:窗口激活后用户改了大小/位置,激活时抓的 rect 就错了。每个主步骤前_refresh_active_rect()重新查询。 - RGBA 模板可能失败,匹配前转 RGB。
- 上轮残留的菜单/面板会破坏匹配,开头复位 UI、结尾清理。
- 手动测试时真人操作会取消工具执行;把后台 automation 安排在无人在场时跑。
- FAILSAFE(鼠标甩到左上角)会中止脚本。
- 窗口不能整关(进程退出);最小化可以,pygetwindow 能恢复。
Screen Saver Wake — 多信号(Win10/11)
别只查 WindowsScreenSaverClass。现代屏保常是"接管态"——前台窗口变 0,顶层被 Microsoft Text Input Application 之类占满,它们不一定就是屏保但会挡住所有 GUI。
检测:结合 FindWindowW('WindowsScreenSaverClass') 与枚举所有覆盖主屏(SM_CXSCREEN×SM_CYSCREEN ±5)的可见顶层窗口;若有非 {WorkerW, Progman, Shell_TrayWnd} 的窗口全覆盖主屏且前台为 0,视为"类屏保态"。
解除:多方法循环——PostMessage(WM_CLOSE) + SendMessage(WM_SYSCOMMAND, SC_CLOSE) 关屏保与全屏接管窗;真实 mouse_event 位移 + keybd_event(SPACE|ESC|ENTER) + 真实点击。
上限:max_seconds=30 放弃并返回明确 ✅/❌,别让用户盯着冻屏。
🔒 锁屏守卫(不自动解锁)
脚本开头先 _is_screen_locked():锁屏则绝不尝试自动解锁(自动解锁路线已证伪),直接退出码 3、零 UI 操作,并通过 notify_cmd 通知用户远程解锁;客户端未运行则退出码 4。
上层调度:退出码 3/4(可恢复态)每 5 分钟重试最多 3 次;其他非 0(真失败)90 秒 ×2 次。重试上限别再加——后面还有兜底备份任务。
通知去重:重试变多后同一天可能刷多条通知。用 guard_notify(kind, msg) + 状态文件,同一天同一 kind 只发 1 条,其余仅写日志。
铁律:锁屏本身不是失败,是"环境不满足 + 等人解锁"的可恢复态;恢复手段是真人远程登录,不是脚本注入输入。锁屏下禁止 taskkill 客户端——杀掉后无法恢复。
可选:领取后余额对账(OCR)
领取成功后读"积分余额"做交叉验证(不再只凭"按钮点中"报成功)。用系统 OCR(winocr,语言包仅 zh-Hans-CN):
- OCR 几乎必丢小数点("1,380.13" → "108013"),启发式按"千分位分组 + 末 2 位当小数"还原。
- 中文 OCR 把 ASCII 逗号读成全角
,,归一化换回半角。 - OCR 会把"积分余额"和数值拆成两行,必须关键词锚定(同行优先 → 右侧邻行 → 全文回退),绝不可"只取全文最大数字"(面板里还有对话数、徽章数等其它数字)。
winocr的bounding_rect仅 word 级,需自行从 words 聚合 line 几何。
Verification Checklist
- [ ]
python scripts/claim_credits.py --test在当前界面能定位每个应可见的模板 - [ ] 完整运行以预期终态结束(按钮文案变"已领取"/"明日再来")
- [ ] 实际结果被确认(积分余额增加,而非仅"无报错")
- [ ] 重复运行命中"今日已领"短路,零 UI 操作、不重复领取
- [ ] 锁屏时退出码 3、零 UI 操作、通知去重生效