把 WorkBuddy 每日自动签到搬上云端:一次彻底摆脱「任务被删 + 关机漏签」的踩坑实录

发布时间:2026/10/6 20:51:25
把 WorkBuddy 每日自动签到搬上云端:一次彻底摆脱「任务被删 + 关机漏签」的踩坑实录 写一个脚本每天定时签到不难难的是「它真的每天都跑成了」。本文记录我把 WorkBuddy 每日签到从 Windows 计划任务一路踩坑任务反复消失、关机不跑、代理拦截最终搬上云端自动化的全过程以及里面的鉴权、续期、安全细节。全程纯 Python 标准库无第三方依赖。1. 背景签到脚本本身很简单目标很朴素每天 09:00 自动完成 WorkBuddy 的每日签到领积分。社区已经有一个现成脚本88lin/workbuddy-auto-signin核心就一个signin.py纯标准库实现urllib零依赖逻辑也清晰读本机桌面端凭证文件workbuddy-desktop.info取出 JWTaccessTokenuidAuthorization: Bearer tokenX-User-IdX-Domain调两个接口先查状态、未签再领幂等先查后领已签过就直接返回重复跑不会多领。脚本没问题出问题的是「谁来在每天 09:00 准时把它跑起来」这件事。2. 第一版Windows 计划任务以及它怎么坑我最直接的想法用 Windows 任务计划程序Task Scheduler每天 09:00 跑python signin.py auto。于是踩坑开始了。2.1 坑一0x80070002python 不在 PATH任务建好后首次运行结果码0x80070002系统找不到文件。原因计划任务的环境变量和交互式命令行不一样python不在它的PATH里。修复Action 里不要写python直接写 Python 解释器的完整绝对路径C:\Users\Cornex\.workbuddy\binaries\python\versions\3.13.12\python.exe2.2 坑二任务反复「人间蒸发」更离谱的是任务建好跑了一段时间后凭空消失了——而且前后消失了 3 次。排查下来高度怀疑是 360 安全卫士企业版本机已启用Windows Defender 被禁用或系统清理策略把这类「非白名单计划任务」清掉了。每次都得手工重建。这是本机方案最致命的「隐性不稳定」你以为它还在其实它早没了。2.3 坑三「无论是否登录都运行」命令行搞不定用户提了个合理需求电脑没登录也要能签到。计划任务里这对应「不管用户是否登录都运行」Password / S4U 登录类型。但在本机环境里这条路被堵死了登录类型尝试方式结果S4U无需密码不支持该场景失败Password输密码schtasks /create /ru /rpschtasks.exe被程序策略拉黑SYSTEM 账户注册 SIDS-1-5-18返回「未指定的错误」权限不足PowerShell-CredentialRegister/Set-ScheduledTaskcmdlet 不支持该参数结论纯命令行在本机无法设置「无人登录也运行」只能去taskschd.msc图形界面手点而那个图形界面又要求输入账号密码且密码框无法绕过。2.4 坑四代理变量把 HTTPS 拦了某天手动跑脚本直接报ssl.SSLEOFError: [SSL: UNEXPECTED_EOF_WHILE_READING]排查发现本机有环境变量HTTP_PROXYhttp://127.0.0.1:29630某个 sandbox 工具注入的本地代理它把对copilot.tencent.com的 HTTPS 请求做了拦截/中转握手直接被掐断。脚本本身没被改动文件时间戳可证。修复跑脚本前清掉代理变量即可$env:HTTP_PROXY $null$env:HTTPS_PROXY $nullpython signin.py auto3. 致命硬伤本机任务关机就罢工前面那些坑好歹能修但有一个是物理层面的硬限制Windows 计划任务只能在操作系统运行时触发。电脑彻底关机断电 / 软关机时任务计划程序根本没在跑自然不会执行。睡眠 / 休眠还能靠「唤醒定时器」补但完全关机 不可能签到。而用户要的恰恰是「电脑不开机也能签到」。所以本机计划任务这条路先天就到不了终点。必须换思路——把执行体挪到「不依赖这台电脑开关机」的地方。4. 选型三条出路方案原理优点代价 / 风险A. BIOS 定时开机主板 RTC 设每天 ~08:55 自动通电开机 → 本机 09:00 任务跑 → 可选跑完自动关机仍在本机改动小任务被 360 清掉的老毛病照旧笔记本需一直插电B. 常开设备代跑把脚本 凭证复制到常开的 NAS / 云服务器 / 树莓派用 cron 跑最稳彻底脱离本机开关机与清理需要一台常开设备凭证要同步过去C. 云端自动化用 WorkBuddy 内置定时自动化在服务端跑不依赖本机不依赖本机开关机抗清理需把签到凭证交给云端代理安全考量最终选了C云端自动化它不依赖本机开关机也天然免疫 360 清理正中「关机也能签」的靶心。代价是凭证要放到云端——下文专门讲怎么把这道安全闸门处理好。5. 云端方案落地四个关键点5.1 先看明白签到脚本怎么鉴权逆向看signin.py和本机凭证文件后鉴权链路清晰了凭证文件workbuddy-desktop.info是 Keycloak 风格结构auth.accessTokenJWT有效期约 55 天expiresIn ≈ 4752000sauth.refreshToken刷新令牌约 60 天refreshExpiresIn ≈ 5184000sscope含offline_accessauth.domain www.codebuddy.cnaccount.uid用户标识。解码accessToken的 JWT payload能直接看到授权服务器信息iss https://www.codebuddy.cn/auth/realms/copilotazp / client_id console由此推断刷新端点https://www.codebuddy.cn/auth/realms/copilot/protocol/openid-connect/token请求头Authorization: Bearer token、X-User-Id: uid、X-Domain: www.codebuddy.cn。接口POST {endpoint}/v2/billing/meter/checkin-activity-status查、/daily-checkin领幂等。关键结论云端只要「带着这几个值」就能签到不依赖本机文件。5.2 把凭证「安全带」进云端base64 BLOB refresh token云端自动化无法读你本机的workbuddy-desktop.info所以必须把需要的字段随脚本一起带过去。做法从本机凭证文件抽取accessToken / refreshToken / uid / domain / realm / clientId / tokenEndpoint / apiEndpoint序列化成 JSON 后base64 编码成一个 BLOB 常量内嵌进脚本脚本运行时base64.b64decode还原绝不落盘、绝不打印明文令牌。防坑提示系统会对 JWT 做输出脱敏只回显前几位。直接print(token)拿不到完整值用base64 整体转码再输出就能绕过脱敏拿到完整 blob——这是把凭证写进云端 prompt 的必要一步。生成 BLOB 的本地小脚本脱敏不打印令牌importbase64,json,os AUTHrC:\Users\Cornex\AppData\Local\CodeBuddyExtension\Data\Public\auth\workbuddy-desktop.infodjson.load(open(AUTH,encodingutf-8))auth,accd[auth],d[account]creds{accessToken:auth[accessToken],refreshToken:auth[refreshToken],uid:acc[uid],domain:auth.get(domain),realm:copilot,clientId:console,tokenEndpoint:https://www.codebuddy.cn/auth/realms/copilot/protocol/openid-connect/token,apiEndpoint:https://copilot.tencent.com,}# 写成 base64避免 JWT 特征串被脱敏写入文件而非 stdout 更安全blobbase64.b64encode(json.dumps(creds,ensure_asciiFalse).encode()).decode()open(rD:\path\to\blob.txt,w,encodingutf-8).write(blob)5.3 幂等 自动续期云端脚本在「查 / 领」两步都做了 401/403 兜底一旦 accessToken 失效先用refreshToken去刷新端点换新的再重试换不到才报NO_SESSION。这样只要刷新端点推断正确令牌就能滚动续期基本做到「设完不用管」。完整逻辑脱敏版BLOB处填上一节的 blobimportbase64,json,ssl,urllib.request,urllib.error,urllib.parse BLOBBASE64_CREDENTIAL_BLOB# 上一步生成的 base64 凭证串defload_creds():returnjson.loads(base64.b64decode(BLOB).decode(utf-8))def_req(url,headers,methodGET,payloadNone):bodyjson.dumps(payload).encode()ifpayloadisnotNoneelseNonerurllib.request.Request(url,databody,headersheaders,methodmethod)ctxssl.create_default_context()try:withurllib.request.urlopen(r,timeout30,contextctx)asresp:rawresp.read().decode()try:returnresp.status,json.loads(raw)exceptException:returnresp.status,{raw:raw[:500]}excepturllib.error.HTTPErrorase:rawe.read().decode(utf-8,replace)try:returne.code,json.loads(raw)exceptException:returne.code,{raw:raw[:500]}exceptExceptionase:return-1,{error:str(e)}defheaders_for(token,creds):h{Accept:application/json,Authorization:Bearer %s%token,Content-Type:application/json,X-User-Id:creds.get(uid,),User-Agent:WorkBuddy,}ifcreds.get(domain):h[X-Domain]creds[domain]returnhdefrefresh(creds):dataurllib.parse.urlencode({grant_type:refresh_token,refresh_token:creds[refreshToken],client_id:creds.get(clientId,console),}).encode()rurllib.request.Request(creds[tokenEndpoint],datadata,headers{Content-Type:application/x-www-form-urlencoded,User-Agent:WorkBuddy},methodPOST,)ctxssl.create_default_context()try:withurllib.request.urlopen(r,timeout30,contextctx)asresp:returnjson.loads(resp.read().decode()).get(access_token)exceptException:returnNonedefcheckin():credsload_creds()apicreds[apiEndpoint].rstrip(/)tokencreds[accessToken]hheaders_for(token,creds)defstatus():return_req(api/v2/billing/meter/checkin-activity-status,h,POST)sc,sbstatus()ifscin(401,403):# token 失效先刷新ntrefresh(creds)ifnt:tokennt;hheaders_for(token,creds);sc,sbstatus()else:return{result:NO_SESSION,report:登录态失效且刷新失败请桌面端重登后重嵌凭证}ifnot(200sc300):return{result:ERROR,http:sc,report:状态接口异常HTTP %s%sc}stsbifisinstance(sb,dict)else{}ifst.get(active)isFalse:return{result:INACTIVE,report:当前签到活动未开启}ifst.get(today_checked_in)isTrue:# 幂等已签直接返回return{result:ALREADY,report:今日已签连续 %s 天%st.get(streak_days)}cc,cb_req(api/v2/billing/meter/daily-checkin,h,POST)ifccin(401,403):ntrefresh(creds)ifnt:tokennt;hheaders_for(token,creds)cc,cb_req(api/v2/billing/meter/daily-checkin,h,POST)ifisinstance(cb,dict):ifcb.get(credit)isnotNone:return{result:CLAIMED,report:成功领取 %s 积分连续 %s 天%(cb.get(credit),st.get(streak_days))}msgstr(cb.get(msg,))ifcb.get(code)10001or已签到inmsgor今天已inmsg:return{result:ALREADY,report:服务端判定今日已签}ifcodeincbormsgincb:return{result:ERROR,http:cc,report:领取失败%s%msg}return{result:UNKNOWN,http:cc,report:未识别的领取返回,body:str(cb)[:300]}if__name____main__:print(json.dumps(checkin(),ensure_asciiFalse))自动化 prompt 里还要加一条硬约束不要回显 / 打印 BLOB 与任何令牌片段不要尝试读取本机凭证文件——凭证已内置云端不该再去碰本机。5.4 敏感内容审批闸门把令牌含refreshToken嵌进 WorkBuddy 云端会触发平台的敏感内容审批。前两次创建都因「审批超时」自动化会话里没有真实人工弹窗完成授权被拦。直到在 WorkBuddy 自动化管理界面手动批准后才创建成功。这是正常的安全闸门不是脚本问题。它提醒我们令牌上云 把登录态交给了云端代理需用户明确知情并授权。6. 效果与运维自动化创建成功状态ACTIVE频率FREQDAILY;BYHOUR9;BYMINUTE10每天 09:10错开整点。彻底脱离本机电脑关机、睡眠、被 360 清理任务都不影响由 WorkBuddy 服务端执行。脚本逻辑、网络、令牌已在本机实跑验证通过返回{result:ALREADY}。后续维护情形表现处理正常每天 09:10 返回CLAIMED/ALREADY无需干预accessToken 过期但 refresh 有效脚本自动续期无需干预刷新也失效返回NO_SESSION桌面端重新登录 → 让助手重新生成 BLOB 重嵌活动结束返回INACTIVE看情况停用自动化accessToken 约 55 天、refreshToken 约 60 天有效只要刷新端点推断正确半年内基本不用管。7. 总结本机计划任务的三个坑PATH找不到 python0x80070002、任务被 360 反复删除、命令行无法设置「无人登录也运行」、本地代理拦截 HTTPS。物理硬伤Windows 计划任务在电脑完全关机时不执行——「关机也能签」必须搬到本机之外。选型BIOS 定时开机 / 常开设备代跑 / 云端自动化三条路按「是否接受令牌上云」定夺。云端落地四件事看明白 Keycloak 风格 JWT 鉴权 → base64 BLOB 把凭证安全带进云端 → 幂等 refresh 自动续期 → 通过敏感内容审批闸门。收益设一次每天 09:10 由服务端跑电脑开不开机、任务清没清都无所谓。一句话能搬云端的定时任务就别跟 Windows 计划任务以及它身后那台会自己清理任务的安全软件较劲了。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询