从抓包到脚本:一次校园签到自动化实践的深度复盘

未分类 3122 字 预计阅读时间: 14 分钟 无~


枯燥的签到与“不安分”的我

大学生活总是伴随着各种各样的规定,其中之一就是我们学校要求的每晚定时签到。这需要打开微信,进入一个特定的小程序,点击几个按钮,才算完成任务。日复一日,这个看似简单的操作开始变得有些枯燥和繁琐。

作为一个对技术充满好奇心的学生,我脑中不禁冒出一个念头:“既然这一切都是在手机上通过网络完成的,那背后一定有网络请求。我能不能捕捉到这个请求,然后用程序去模拟它,从而实现自动签到呢?”

这个想法让我兴奋不已。这不仅能将我从重复的劳动中解放出来,更是一次绝佳的学习和实践机会。于是,我决定开启这次探索之旅,用代码去“欺骗”服务器,让它以为我每天都准时地手动签到。

Fiddler 闪亮登场

要模拟网络请求,第一步就是要知道这个请求到底长什么样。这时,我的老朋友——网络抓包工具 Fiddler 闪亮登场。Fiddler 是一个强大的网络调试代理工具,它可以像一个“中间人”一样,记录所有客户端和服务器之间的 HTTP(S) 通信。

我的计划是:

  1. 在我的电脑上打开 Fiddler,并设置好解密 HTTPS 流量的选项。
  2. 打开 PC 端的微信,找到那个签到小程序。
  3. 在小程序里手动完成一次签到操作。
  4. 在 Fiddler 捕获到的大量请求中,找到关键的那一个。

配置 Fiddler 解密 HTTPS

这一步是整个抓包过程中最关键,也最容易出问题的地方。小程序和服务器之间的通信几乎都是经过 HTTPS 加密的。如果不进行解密,我们用 Fiddler 抓到的将只是一堆乱码。

解密的原理是 Fiddler 伪装成一个中间人,对客户端(微信小程序)来说,它伪装成服务器;对服务器来说,它又伪装成客户端。为了让客户端信任这个“假服务器”,我们需要在电脑上安装 Fiddler 生成的根证书。

步骤大致如下:

  • 在 Fiddler 的 Tools -> Options -> HTTPS 菜单中,勾选 Capture HTTPS CONNECTsDecrypt HTTPS traffic
  • 点击 Actions 按钮,选择 Trust the Fiddler Root Certificate,并按照提示在系统中安装证书。
  • 配置完成后,PC 微信发出的 HTTPS 请求就能被 Fiddler 成功解密,以明文形式展示出来。

操作开始!当我点击“签到”按钮的那一刻,Fiddler 的会话列表里瞬间滚动过几条新的记录。经过一番排查,我很快锁定了一个目标:一个向 form.qun100.com 域名发送的 POST 请求。这个请求的 URL、请求头和请求体都包含了丰富的信息,看起来就是它了!

解构 API 请求

捕获到请求只是第一步,真正的核心在于理解它。我像侦探一样,仔细分析着这个请求的每一个细节:

  • 请求 URL:https://form.qun100.com/v1/xxxxxxxxxxxxxxxxxxx/form_data
    • 这是一个典型的 RESTful API 接口,URL 中包含了一串看似是表单 ID 的数字。
  • 请求方法:POST
    • 这表明我的客户端正在向服务器提交数据,完全符合“签到”这个动作的性质。
  • 请求头 (Headers):
    • 这里面包含了很多关键信息,比如 Content-Type: application/json 说明了我们提交的是 JSON 格式的数据。
    • User-Agent 则详细描述了我的客户端环境(微信PC版、Windows系统等),模拟时最好也带上,让请求看起来更真实。
    • 最重要的发现是 Authorization 这个字段!它的值是一长串加密字符。我立刻意识到,这就是我的“身份令牌”(Token),服务器通过它来识别我是谁。这也是整个自动化过程中最关键、也最棘手的部分。
  • 请求体 (Body):
    • 这是一个 JSON 对象,里面清晰地展示了我要提交的数据。我甚至在里面看到了我的名字,以及一些和表单问题相关的 ID。那些看起来像乱码的键名,很可能是表单中每个问题的唯一标识符。

至此,签到请求的全部秘密都已暴露在我面前。下一步,就是将这些信息转化为代码。

编写 Python 模拟脚本

有了完整的请求结构,我选择了世界上最优雅的语言——Python,并使用其强大的 requests 库来打造我的自动化脚本。我的思路很简单:将 Fiddler 中看到的请求信息,原封不动地用 Python 代码“复刻”一遍。

但在编写时,我遇到了一个小插曲。直接运行请求时,Python 报出了 SSL: CERTIFICATE_VERIFY_FAILED 错误。这是因为我的脚本运行时,系统无法验证 form.qun100.com 的 SSL 证书。这可能是因为服务器证书链不完整,或者受到了某种网络环境的干扰。

对于个人项目,最直接的解决方案是在请求时添加 verify=False 参数,告诉 requests 库“我信任这个网站,请跳过证书验证”。请注意:在生产环境或处理敏感数据的项目中,这绝对是一个危险的操作,因为它会使你面临中间人攻击的风险。 但对于我们这个学习性质的签到小脚本,这无疑是最便捷的方法。

以下就是我最终成型的脚本。它精确地模拟了小程序签到的全过程:

import requests
import json
import ssl
import urllib3

# 禁用SSL警告(在禁用证书验证时,控制台不会输出一堆警告)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def simulate_form_request():
    """模拟向 form.qun100.com 发送POST签到请求"""

    # 目标URL
    url = "https://form.qun100.com/v1/1715920xxxxxx759553/form_data"

    # 构造请求头,大部分从Fiddler直接复制
    headers = {
        "Host": "form.qun100.com",
        "Connection": "keep-alive",
        "Content-Type": "application/json",
        "xweb_xhr": "1",
        "Client-Form-Id": "1715920xxxx20759553",
        "Client-App-Id": "wxfc4ef6dxxxxx3373",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf254032b) XWEB/13773",
        # !!! 这是关键的身份令牌,需要定期更新 !!!
        "Authorization": "保密",
        "ver": "3.15.0",
        "Accept": "*/*",
        "Sec-Fetch-Site": "cross-site",
        "Sec-Fetch-Mode": "cors",
        "Sec-Fetch-Dest": "empty",
        "Referer": "https://servicewechat.com/wxfc4ef6d5xxxx3373/244/page-frame.html",
        "Accept-Encoding": "gzip, deflate, br",
        "Accept-Language": "zh-CN,zh;q=0.9"
    }

    # 构造请求体,也就是要提交的数据
    data = {
        "fid": "",
        "subscribe": {
            "qgPso1tQCJF6E-xxxxxxxbvtWFqKvN5wvMDFjCop400": 1,
            "vj0_jH-hZaQ3pSSN_icqYZt5NExxxxvlA8Q3dTfQJ68": 1,
            "9frpvZ2b6QJAUgG83Xkgxxxxg0JqjqqKJ7B7I33G7jE": 1
        },
        "catalogs": [
            {
                "cid": "1715920xxxxxx367233",
                "type": "WORD",
                "value": "xxx"
            }
        ],
        "showQuestions": ["1715920xxxxxx367233"],
        "examUsedTime": None,
        "formVersion": 3,
        "userCommonInfo": {
            "userName": "xxx"
        }
    }

    print("=" * 50)
    print("开始模拟签到请求...")

    try:
        # 发送POST请求,verify=False是为了忽略SSL证书验证
        response = requests.post(url, headers=headers, json=data, timeout=30, verify=False)

        print("请求发送成功!")
        print(f"服务器响应状态码: {response.status_code}")

        # 尝试以JSON格式打印响应内容
        try:
            print(f"响应内容: {json.dumps(response.json(), indent=2, ensure_ascii=False)}")
        except json.JSONDecodeError:
            print(f"响应内容 (非JSON): {response.text}")

    except requests.exceptions.RequestException as e:
        print(f"请求失败: {e}")

    print("=" * 50)

if __name__ == "__main__":
    simulate_form_request()

当我第一次在终端运行 python your_script_name.py 并看到服务器返回 200 状态码和成功的 JSON 数据时,我激动地差点跳起来——成功了!我用代码完成了一次签到!

Token 的“保鲜期”

正当我沉浸在成功的喜悦中时,一个问题浮现出来:那个 Authorization 的 Token 是永久有效的吗?

直觉告诉我,不太可能。出于安全考虑,这种令牌通常都有一个“保鲜期”,这是一种防止令牌泄露后被无限期滥用的常见安全策略。果不其然,在享受了两天的自动签到后,第三天我的脚本收到了一个表示“未授权”或“令牌失效”的错误响应。

我再次打开 Fiddler 抓包,发现 Authorization 的值已经变了。原来,这个 Token 大约每三天会更新一次

这意味着,我无法做到“一劳永逸”的完全自动化。我必须每隔三天,就手动操作一次小程序,用 Fiddler 捕获新的 Token,然后把它更新到我的 Python 脚本里。这形成了开发领域中常见的“猫鼠游戏”的缩影:开发者加上了安全机制,而我们则需要找到适应这种机制的方法。

让脚本定时运行

虽然需要手动更新 Token,但每天运行脚本这件事本身也可以自动化。总不能每天晚上都记着自己去点一下运行按钮吧?这里,我们可以使用操作系统的计划任务功能。

  • 对于 Windows 用户: 可以使用“任务计划程序 (Task Scheduler)”。
    1. 创建一个新任务。
    2. 设置触发器,比如“每天”的晚上 10 点。
    3. 设置操作为“启动程序”,程序或脚本指向你的 Python 解释器 (python.exe),参数填写你的脚本文件的完整路径 (D:\path\to\your_script.py)。
  • 对于 macOS 或 Linux 用户: 可以使用 cron 命令,这是一个强大的定时任务工具。
    • 在终端输入 crontab -e
    • 添加一行类似 0 22 * * * /usr/bin/python3 /path/to/your_script.py 的命令,即可实现每天 22:00 自动执行脚本。

这样一来,我只需要每三天花一分钟更新一下 Token,签到的任务就彻底交给了电脑。

技术探索的边界

完成这个项目后,我也不禁思考:这样做对吗?这算不算一种“作弊”?

从本质上讲,我的脚本只是模拟了客户端的合法行为,没有攻击服务器,也没有窃取他人的数据。我的初衷纯粹是技术探索和解决个人生活中的一个小小不便。我认为,当这种探索是出于学习目的,并且不损害系统安全、不影响他人利益、不违反法律法规时,它是值得鼓励的。

但我们也要认识到,这种行为行走在灰色地带。如果滥用,比如用于商业牟利或恶意攻击,性质就完全变了。因此,对技术的敬畏心和对规则的尊重是每个技术爱好者都应具备的品质。

总结与展望

这次从手动签到出发的自动化实践,带给我的远不止是省下几秒钟时间那么简单。

  • 从想法到实现: 我完整地经历了一次“发现问题 -> 分析问题 -> 解决问题”的技术实践,这种正向反馈是学习路上最宝贵的激励。
  • 技术工具的运用: 我更加熟练地掌握了 Fiddler 和 Python requests 库这对黄金搭档,深刻理解了 HTTP 请求的本质、HTTPS 解密的原理和 API 交互的逻辑。
  • 自动化思维: 这次经历让我对“自动化”有了更深的理解。它不一定非要是完美的、一劳永逸的,哪怕只是将 99% 的重复工作自动化,也是巨大的进步。

当然,我也思考了完美的解决方案:如果能逆向分析出小程序登录和获取 Token 的逻辑,并用代码模拟,就可以实现真正的全自动。但这需要投入更多的时间去研究微信小程序的加密和认证机制,复杂度远超现在。

对于目前的结果,我已经非常满意。它就像一个半自动的“签到助手”,每三天只需要我“喂”给它一个新的令牌,它就能在接下来的日子里默默地为我完成任务。

或许,这就是技术带给我们的乐趣——在规则的边界内,用自己的智慧和代码,去理解这个数字世界的运作方式,并创造出属于自己的便捷和优雅。而这段旅程,本身就比终点更有意义。

天山云水 上下一白
最后更新于 2025-06-23