1. 从手动打卡到自动化:一个真实需求驱动的项目拆解
每天睁眼第一件事就是摸手机打卡,这种体验相信不少人都有过。不管是健康信息上报、日常考勤签到,还是各类平台的每日任务,重复性的手动操作消耗的不只是时间,更是一种持续的心理负担。我最初做这个自动化项目的动机特别朴素:连续三个月每天早上被闹钟叫醒后第一件事就是打开手机完成打卡,偶尔睡过头忘了,还得补卡写说明,实在受不了了。
这个项目的核心思路很直接:用 GitHub Actions 这个免费的持续集成服务,配合定时任务触发机制,把原本需要人工完成的打卡、签到流程全部自动化。GitHub Actions 提供了定时触发的能力,你可以把它理解成一个云端闹钟,到点就自动执行你预设好的脚本。脚本里做的事情就是模拟你平时手动操作的那些步骤——登录、填写表单、提交数据。整个过程跑在 GitHub 的服务器上,不需要你自己的电脑或手机开机,也不需要额外的服务器成本。
适合谁来参考这个方案?如果你有编程基础,哪怕只是入门水平,能看懂简单的 Python 或 JavaScript 代码,就可以跟着做。如果你完全不懂代码,但愿意花点时间学习基础概念,这个项目的门槛也不算高。我见过不少非科班出身的朋友,照着类似的思路把自己的日常签到任务自动化了。关键在于理解整个流程的逻辑,而不是死记硬背代码。
需要提前说清楚的是,这个方案涉及的是你自己账号的自动化操作,前提是你拥有账号的合法使用权,并且自动化操作不违反平台的服务条款。我个人的原则是:只自动化自己手动也会做的操作,不涉及任何批量注册、刷量、爬取他人数据等行为。这一点在后面还会反复强调,因为技术本身是中性的,用在哪里、怎么用,取决于使用者的判断。
2. 整体架构设计:为什么选择 GitHub Actions
2.1 方案选型的核心考量
市面上能实现定时任务的方案不少,为什么偏偏选 GitHub Actions?我对比过几种常见方案,最后确定 GitHub Actions 的原因有这么几个。
第一是零成本。GitHub 对公开仓库的 Actions 使用是完全免费的,私有仓库每月也有 2000 分钟的免费额度。对于每天跑一两次、每次几十秒的打卡任务来说,这个额度绰绰有余。你不需要买服务器,不需要租云函数,不需要担心账单。
第二是环境稳定。GitHub 的服务器可用性很高,不会因为你本地断网、电脑关机、手机没电而错过执行时间。我试过用本地电脑的定时任务来做这件事,结果有一次出差忘了带电脑,直接断了好几天。云端执行就没有这个问题。
第三是配置简单。你只需要在仓库里放一个 YAML 配置文件,写清楚什么时候执行、执行什么命令,剩下的 GitHub 会帮你搞定。不需要配置服务器环境、不需要处理网络端口、不需要考虑运维。
第四是版本管理天然集成。你的脚本、配置、甚至打卡记录的日志,都可以直接存在仓库里,每次修改都有 commit 记录,出了问题可以随时回滚。这一点对于需要长期维护的自动化任务来说特别重要。
当然也有局限性。GitHub Actions 的定时任务并不是精确到秒的,官方文档说可能会有几分钟到十几分钟的延迟,尤其是在任务高峰期。如果你的打卡有严格的时间窗口要求,比如必须在某个时间点之前完成,那就需要把触发时间设置得早一些,留出足够的缓冲。另外,GitHub Actions 的运行环境每次都是全新的,不会保留上一次运行的状态,所以如果需要记录打卡历史,得想办法持久化存储。
2.2 核心模块拆解
整个自动化流程可以拆成四个核心模块,每个模块各司其职。
触发模块负责决定什么时候开始执行。GitHub Actions 支持 cron 表达式来定义定时任务,格式和 Linux 系统的 crontab 类似,但用的是 UTC 时间。比如你想让任务在北京时间早上 7 点执行,对应的 UTC 时间就是前一天晚上 11 点,cron 表达式要写成0 23 * * *。这里有个容易踩的坑:很多人直接写0 7 * * *,结果发现任务在下午 3 点才跑,就是因为忘了时区转换。
认证模块负责处理登录态。打卡和签到本质上都是需要身份认证的操作,你得先证明“你是你”。常见的认证方式有两种:一种是直接用账号密码登录,另一种是使用已经登录后获取的 Cookie 或 Token。前者实现简单但安全性稍差,后者更安全但需要定期更新凭证。我个人的做法是优先使用 Token 或 Cookie,并且把这些敏感信息存在 GitHub 仓库的 Secrets 里,而不是直接写在代码中。
业务逻辑模块是核心中的核心,负责模拟具体的打卡操作。这部分需要你分析目标网站或应用的请求结构,找到提交打卡数据的那一个接口,然后用代码构造出相同的请求。听起来复杂,实际上用浏览器的开发者工具就能完成大部分分析工作。打开开发者工具的网络面板,手动操作一次打卡,观察发出了哪些请求,找到关键的那个,把请求方法、URL、请求头、请求体都记录下来。
通知模块是可选的,但强烈建议加上。任务跑完了,你总得知道成功还是失败。最简单的做法是在脚本里加一段逻辑,成功或失败时给自己发一封邮件,或者通过某种消息推送服务发一条通知。我一开始没加通知,结果有段时间打卡一直失败,过了两周才发现,白白断了好久的记录。
2.3 数据流转与安全边界
整个流程的数据流向是这样的:GitHub Actions 按照 cron 表达式触发 → 拉取仓库代码 → 安装依赖 → 从 Secrets 读取敏感凭证 → 执行打卡脚本 → 脚本向目标服务器发送请求 → 根据响应判断结果 → 发送通知 → 结束运行。
这里面有几个安全边界需要特别注意。第一,敏感凭证绝对不能硬编码在代码里。GitHub 提供了 Secrets 功能,你可以在仓库设置里添加加密的环境变量,Actions 运行时才能读取到。第二,日志输出要小心。GitHub Actions 的运行日志是公开可见的(对于公开仓库),所以脚本里不要打印任何敏感信息,比如完整的 Cookie、Token、密码等。第三,最小权限原则。如果你的打卡脚本只需要读取和提交打卡数据,就不要给它额外的权限。
注意:使用自动化工具操作任何平台前,请先确认该平台的服务条款是否允许此类行为。本文讨论的技术方案仅供学习参考,使用者需自行承担合规责任。
3. 核心细节解析:从请求分析到脚本实现
3.1 如何分析打卡接口
分析接口是整个项目中最关键的一步,也是最需要耐心的一步。我以常见的健康打卡场景为例,讲讲具体的操作流程。
首先,在电脑浏览器上打开目标网站或应用,按 F12 打开开发者工具,切换到 Network(网络)面板。勾选“Preserve log”(保留日志),这样页面跳转时请求记录不会丢失。然后手动完成一次完整的打卡操作,从点击打卡按钮到看到成功提示,这期间产生的所有请求都会被记录下来。
接下来就是筛选。打卡操作通常会触发多个请求,你需要找到真正提交数据的那一个。我的经验是看这几个特征:请求方法是 POST 的优先看,URL 里包含 submit、save、report、checkin 这类关键词的优先看,请求体里有你填写的表单数据的优先看。找到疑似请求后,点击查看详情,重点看 Request Headers(请求头)和 Request Payload(请求体)。
请求头里需要关注的是 Cookie、Authorization、User-Agent 这几个字段。Cookie 和 Authorization 是身份凭证,User-Agent 标识客户端类型。有些平台会校验 User-Agent,如果发现不是正常的浏览器或 App,可能会拒绝请求。请求体里则是具体的打卡数据,比如体温、位置、健康状况等。
把这些信息记录下来之后,你可以用 curl 命令在本地先测试一下,确认构造的请求能成功提交。比如:
curl -X POST 'https://example.com/api/checkin' \ -H 'Content-Type: application/json' \ -H 'Cookie: sessionid=your_session_id' \ -H 'User-Agent: Mozilla/5.0 ...' \ -d '{"temperature":"36.5","location":"xxx","status":"healthy"}'如果返回的结果和手动操作一致,说明请求构造正确,接下来就可以用代码来实现了。
3.2 凭证管理与 Secrets 配置
凭证管理是安全的核心。我见过有人在公开仓库里直接写账号密码,结果被爬虫扫到,账号被盗用。这种低级错误绝对不能犯。
GitHub 的 Secrets 功能用起来很简单。进入仓库的 Settings → Secrets and variables → Actions,点击 New repository secret,把需要保密的变量名和值填进去。比如你可以添加一个叫CHECKIN_COOKIE的 Secret,值是登录后的 Cookie 字符串。在 Actions 的 YAML 文件里,通过${{ secrets.CHECKIN_COOKIE }}来引用。
这里有个细节需要注意:Cookie 是有有效期的,过期之后打卡就会失败。不同的平台有效期不一样,有的几天,有的几周。你需要定期检查打卡是否正常,如果发现失败是因为 Cookie 过期,就重新获取并更新 Secret。为了减少手动更新的频率,可以在脚本里加一个判断:如果响应提示未登录,就发送一条通知提醒你去更新凭证。
还有一种更优雅的做法是自动刷新凭证。如果平台提供了 refresh token 机制,你可以在脚本里用 refresh token 换取新的 access token,然后把新 token 存回 Secrets。不过 GitHub Actions 默认没有权限修改 Secrets,需要额外配置一个 Personal Access Token 来实现。这个方案复杂度较高,适合对安全性要求特别高的场景。
3.3 脚本编写的关键技巧
脚本语言的选择上,Python 是最常见的选择,因为它的 requests 库处理 HTTP 请求非常方便,代码也简洁易读。当然用 Node.js 的 axios 或者原生的 fetch 也完全可以,看你个人熟悉哪个。
写脚本的时候有几个技巧可以分享。第一,加上重试机制。网络请求偶尔失败是正常的,不要一次失败就放弃。我一般会设置最多重试 3 次,每次间隔几秒。第二,做好异常处理。用 try-except 把可能出错的代码包起来,出错时打印清晰的错误信息,方便排查。第三,记录关键日志。每次运行的时间、请求的结果、失败的原因,都记下来。这些日志在排查问题时非常有用。
一个典型的打卡脚本结构大概是这样:
import requests import os import time def checkin(): cookie = os.environ.get('CHECKIN_COOKIE') headers = { 'Cookie': cookie, 'User-Agent': 'Mozilla/5.0 ...', 'Content-Type': 'application/json' } data = { 'temperature': '36.5', 'status': 'healthy' } for attempt in range(3): try: resp = requests.post( 'https://example.com/api/checkin', headers=headers, json=data, timeout=30 ) if resp.status_code == 200: result = resp.json() if result.get('success'): print(f'打卡成功: {result}') return True else: print(f'打卡失败: {result}') else: print(f'请求异常: {resp.status_code}') except Exception as e: print(f'第 {attempt+1} 次尝试出错: {e}') time.sleep(5) return False if __name__ == '__main__': success = checkin() if not success: # 发送失败通知 pass这段代码虽然简单,但包含了几个关键要素:从环境变量读取凭证、设置请求头、构造请求体、重试机制、异常处理、结果判断。你可以根据自己的实际需求调整。
3.4 定时触发的时区陷阱
前面提到了时区问题,这里再展开说一下。GitHub Actions 的 cron 表达式使用的是 UTC 时间,而北京时间是 UTC+8。这意味着如果你想让任务在北京时间早上 7 点执行,cron 表达式应该写成0 23 * * *,也就是 UTC 时间的 23 点,对应北京时间第二天早上 7 点。
这个换算看起来简单,但实际写的时候很容易搞混。我的建议是先在纸上画一个时间对照表,把你要执行的时间点对应的 UTC 时间算清楚,再写 cron 表达式。另外,GitHub Actions 的定时任务可能会有延迟,尤其是在整点的时候,因为那个时间段任务特别多。如果你对时间比较敏感,可以把执行时间设置得稍微早一点,比如提前 15 到 30 分钟。
还有一个坑是:GitHub Actions 的定时任务在仓库连续 60 天没有活动后会自动暂停。也就是说,如果你的仓库只有定时任务在跑,没有任何其他的 commit 或操作,60 天后定时任务就会停止。解决办法很简单,定期往仓库里提交一点东西,或者手动触发一次 workflow。我一般会在脚本里加一个逻辑,每次运行后自动更新一个记录文件并提交,这样既保留了运行日志,又避免了定时任务被暂停。
4. 完整实操流程:从零搭建自动化打卡
4.1 仓库初始化与目录结构
第一步是创建一个新的 GitHub 仓库。如果你不介意代码公开,可以创建公开仓库,这样 Actions 的使用额度完全免费。如果介意,就创建私有仓库,每月有 2000 分钟的免费额度,对于每天跑一两次的任务来说也够用。
仓库创建好之后,建议按下面的结构组织文件:
repo/ ├── .github/ │ └── workflows/ │ └── checkin.yml ├── scripts/ │ └── checkin.py ├── requirements.txt └── README.md.github/workflows/目录是 GitHub Actions 规定的存放 workflow 文件的位置,这个路径不能改。scripts/目录放你的业务脚本。requirements.txt列出 Python 依赖,比如requests。README.md可以写一些说明,方便自己以后回顾。
4.2 Workflow 文件编写详解
Workflow 文件是 YAML 格式的,定义了整个自动化流程。下面是一个完整的示例:
name: Daily Checkin on: schedule: - cron: '0 23 * * *' workflow_dispatch: jobs: checkin: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.11' - name: Install dependencies run: pip install -r requirements.txt - name: Run checkin script env: CHECKIN_COOKIE: ${{ secrets.CHECKIN_COOKIE }} run: python scripts/checkin.py逐段解释一下。name是这个 workflow 的名称,随便起。on定义触发条件,schedule下面是 cron 表达式,workflow_dispatch允许你手动触发,方便测试。jobs下面是具体的任务,runs-on指定运行环境,ubuntu-latest是最常用的。steps是步骤列表,每一步做一件事:拉取代码、安装 Python、安装依赖、运行脚本。
env部分把 Secrets 里的凭证注入到环境变量中,脚本里通过os.environ.get()读取。这样凭证就不会出现在代码或日志里。
4.3 本地测试与调试方法
在把代码推到 GitHub 之前,强烈建议先在本地测试通过。本地测试的好处是调试方便,能看到完整的报错信息,不用反复提交代码等 Actions 运行。
本地测试的步骤:先安装依赖pip install -r requirements.txt,然后设置环境变量。Linux 或 macOS 下用export CHECKIN_COOKIE='your_cookie',Windows 下用set CHECKIN_COOKIE=your_cookie。然后直接运行python scripts/checkin.py,观察输出。
如果本地测试成功,再推到 GitHub。推上去之后,进入仓库的 Actions 页面,找到对应的 workflow,点击 Run workflow 手动触发一次,看看在 GitHub 的环境里能不能正常运行。如果失败,点进去看日志,根据报错信息排查。
常见的报错有这么几类:依赖没装好,检查 requirements.txt 是否完整;环境变量没读到,检查 Secrets 名称是否和代码里一致;请求被拒绝,可能是 Cookie 过期或 User-Agent 不对;超时,可能是网络问题,加长 timeout 或加重试。
4.4 通知机制的接入
通知机制能让你的自动化任务形成闭环。最简单的通知方式是邮件,GitHub Actions 本身在 workflow 失败时会发邮件通知,但成功时不会。如果你想在成功时也收到通知,或者想用其他渠道(比如即时通讯工具),就需要自己实现。
我常用的方案是使用一个支持 Webhook 的消息推送服务。在脚本的最后,根据打卡结果调用对应的 Webhook URL,发送一条消息。比如:
import requests def send_notification(success, message): webhook_url = os.environ.get('NOTIFY_WEBHOOK') if not webhook_url: return content = f"打卡{'成功' if success else '失败'}: {message}" try: requests.post(webhook_url, json={'content': content}, timeout=10) except Exception as e: print(f'通知发送失败: {e}')把 Webhook URL 也存到 Secrets 里,通过环境变量读取。这样每次运行完,你都能及时知道结果,不用专门去 GitHub 上看。
提示:通知内容里不要包含任何敏感信息,比如 Cookie、Token、完整的请求响应等。只发成功或失败的状态和简要说明即可。
5. 常见问题与排查技巧实录
5.1 打卡失败的典型原因
打卡失败的原因五花八门,我把自己踩过的坑和帮别人排查过的问题整理成了一张表,方便对照排查。
| 现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 提示未登录 | Cookie 过期 | 检查响应内容是否包含登录相关提示 | 重新获取 Cookie 并更新 Secret |
| 请求返回 403 | User-Agent 被识别 | 对比手动操作时的 User-Agent | 使用与浏览器一致的 User-Agent |
| 请求返回 400 | 请求体格式错误 | 对比手动操作的请求体 | 检查字段名、数据类型是否正确 |
| 任务未执行 | cron 表达式错误 | 检查 Actions 页面是否有运行记录 | 确认时区换算和表达式格式 |
| 任务延迟执行 | GitHub 调度延迟 | 查看实际执行时间 | 提前设置触发时间,留出缓冲 |
| 定时任务停止 | 仓库 60 天无活动 | 检查 Actions 页面是否有暂停提示 | 定期提交代码或手动触发 |
| 脚本报错 | 依赖缺失或版本问题 | 查看 Actions 运行日志 | 完善 requirements.txt,固定版本号 |
这张表基本覆盖了 90% 以上的常见问题。遇到失败时,第一步永远是看日志,日志里通常有明确的错误信息。第二步是对比手动操作,看看自动化请求和手动请求有什么差异。第三步是缩小范围,把复杂的脚本拆成简单的步骤,逐个验证。
5.2 凭证过期的应对策略
凭证过期是自动化打卡最常见的失败原因,没有之一。Cookie 的有效期从几小时到几个月不等,取决于平台的策略。我遇到过最短的只有 2 小时,也遇到过能撑一个月的。
应对策略有这么几种。第一种是定期手动更新,比如每周检查一次,发现过期就重新获取。这种方式最笨但最可靠。第二种是自动检测加通知,脚本里判断响应是否提示未登录,如果是就发通知提醒你更新。这种方式减少了检查频率,但还是要手动操作。第三种是自动刷新,如果平台支持 refresh token,可以在脚本里自动换取新的 access token。这种方式最省心,但实现复杂度最高,而且不是所有平台都支持。
我个人的做法是第二种加第三种结合:优先尝试自动刷新,刷新失败就发通知。这样大部分时候不用管,偶尔需要手动介入。
5.3 避免被平台风控的经验
自动化操作和手动操作在平台看来是有区别的,如果行为太规律、太机械,可能会触发风控。我总结了几条经验,可以降低被风控的概率。
第一,请求间隔要合理。不要一秒钟发好几个请求,模拟正常人的操作节奏。打卡这种操作,一天一次就够了,不要频繁请求。
第二,User-Agent 要真实。用常见的浏览器或 App 的 User-Agent,不要用脚本默认的。有些平台会检查 User-Agent,发现异常就直接拒绝。
第三,请求头要完整。除了 Cookie 和 User-Agent,Referer、Origin、Accept 这些头也尽量带上,和手动操作保持一致。
第四,执行时间要分散。如果你的打卡时间固定在每天同一秒,时间长了可能会被注意到。可以在 cron 表达式的基础上,在脚本里加一个随机的延迟,比如 0 到 300 秒之间随机。
第五,不要共享凭证。你的 Cookie 只在你自己的脚本里用,不要分享给别人,也不要用别人的。共享凭证不仅不安全,还可能导致账号被关联风控。
注意:以上经验是为了让自动化操作更接近正常使用行为,而不是为了规避平台的安全机制。如果平台明确禁止自动化操作,请遵守平台规定,不要强行使用技术手段绕过。
5.4 日志与监控的实用技巧
日志是排查问题的生命线。GitHub Actions 的日志默认保留 90 天,对于排查近期问题足够了。但如果想长期追踪打卡情况,最好自己额外记录一份。
我的做法是在仓库里建一个logs/目录,每次运行后把结果追加到一个日志文件里,然后自动提交。这样既能长期保存记录,又能保持仓库有活动,避免定时任务被暂停。日志格式可以很简单,一行一条记录,包含时间、结果、备注:
2024-01-15 07:02:33 SUCCESS 打卡成功 2024-01-16 07:03:12 SUCCESS 打卡成功 2024-01-17 07:01:45 FAILED Cookie过期这样一眼就能看出哪几天失败了,失败原因是什么。如果连续失败,就说明需要更新凭证或者检查脚本了。
监控方面,除了前面说的通知机制,还可以利用 GitHub Actions 自带的状态徽章。在 README 里加上 workflow 的状态徽章,打开仓库首页就能看到最近一次运行是成功还是失败,非常直观。
6. 扩展思路:从打卡到更多自动化场景
这套方案的适用范围远不止打卡签到。任何需要定时执行、涉及 HTTP 请求的重复性任务,都可以用类似的思路来实现。比如定时获取某个网站的数据并保存、定时发送提醒消息、定时检查某个服务的状态并在异常时告警、定时备份某些数据到指定位置等等。
扩展的时候,核心逻辑是不变的:分析手动操作的请求、提取关键参数、用代码模拟请求、设置定时触发、加上通知和日志。变化的只是具体的业务逻辑和请求细节。你可以把这套框架当成一个模板,遇到新的自动化需求时,替换掉业务逻辑部分就行。
我在实际使用中最大的体会是:自动化的价值不在于省下那几分钟操作时间,而在于消除了“别忘了”这个心理负担。以前每天都要惦记着打卡这件事,现在完全不用想,到点自动完成,失败了还会通知我。这种安心感才是自动化真正的意义。另外,这套方案跑起来之后,建议定期回顾一下日志,看看有没有异常趋势,比如失败率突然升高、执行时间越来越晚等,及时发现潜在问题。