CB791135F336AB4B3460F89584993C4A

感谢同学 Vampirehh 提供源代码 👏

我提供了 Github Actions 定时运行的思路 😉

鉴于原作者没有公开代码,我也就不公开 GitHub 仓库了。由于思路和整体流程还是很简单的,我这里重新整理一下。

前期准备

  1. PC端抓包工具:官网下载 Fiddler Classic 就可以。
  2. PC端登录微信。
  3. Python 以及 requests 模块。
  4. 想要每天自动执行的话还需要 GitHub 账号或者网络服务器一台,相比于后者注册个 GitHub 要简单的多。

CB791135F336AB4B3460F89584993C4A

Thanks to my classmate Vampirehh for providing the source code 👏

I came up with the idea of running it on a schedule with GitHub Actions 😉

Since the original author didn’t make the code public, I won’t publish the GitHub repository either. Because the idea and the overall process are quite simple, I’ll reorganize it here.

Preparation

  1. Packet capture tool on PC: just download Fiddler Classic from the official site.
  2. Log in to WeChat on PC.
  3. Python and the requests module.
  4. To run it automatically every day, you also need a GitHub account or a web server; compared to the latter, registering a GitHub account is much simpler.

打卡代码编写

大体思路还是很简单的,我们需要用抓包工具获取到打卡签到时发送的数据包,再使用 Python 的 requests 模块模拟这个请求。其实这个思路在我刚刚读研的时候就有,只是当时我卡在了下面的第一步。😅

Fiddler 抓取 Https

我本身代码能力一般,又不懂网络编程,不知道是不是所有微信小程序都需要使用 Https 协议。我们学院的信仰不息小程序使用的是 Https 协议,在我研一的时候我就尝试过使用 Fiddler 去抓包,可就是抓不到。直到后来看到了Vampirehh同学提供的代码,我问他我怎么抓不到,他告诉我需要设置一下。于是我打开了 Bing, 搜索之后发现 Fiddler 在默认情况下不会捕获 Https,需要自己手动设置一下。

打开 Fiddler,选择 Tools -> Options; 在 Options 选项卡中 选择 Https,勾选 Capture Https CONNECTs ,Decrypt HTTPS ttaffic 和 Ignore server certificate errors(unsafe)。最后点击 OK。

image-20211106175554372

image-20211106175702394

抓包开始

接下来,我们就可以打开信仰不息小程序,进行抓包工作了。

PC 端登录小程序。

image-20211106180333615

填写基本信息,点击提交按钮。

动画

接下来,在 Fiddler 界面中可以看到响应结果是 200 主机(Host) 是 www.dmuistac.com 的一个请求。我们点击这个请求,查看具体的信息。

image-20211106183311155

从具体的信息中,实际上我就就可以通过在浏览器中访问原始请求数据来进行签到了。

image-20211106184905008

比如,我可以通过访问如下地址来进行签到。(你点一下就帮我签到一次😁)

https://www.dmuisatc.com/DMU_WEB/student_5/info/?jsonnumber=1120200298&jsonname=汪广鑫&jsonclass=2020级硕士研究生中队&morning=36.4℃&afternoon=36.4℃&night=36.4℃&jsonbody=1&jsonbodychangeinfo=&textarea=在校&textprople=同学&jsontouch=1&jsontouchchangeinfo=0&jsonisolate=1&jsonisolatechangeinfo=0&latitude=38.91369&longitude=121.61476

这个链接是这样组成的。

image-20211106185715185

浏览器访问的结果就是下面这样。

image-20211106185351851

为了进一步证明我们的浏览器访问是可以签到的,我们可以点击微信小程序的我的填报按钮,来查看 FIddler 最新抓到的包,可以看到最近一次签到的时间。

image-20211106190025042

可以看到今天最后一次填报的时间就是我刚刚访问浏览器的时间。

image-20211106190220552

Writing the Check-in Script

The general idea is quite simple: we use a packet capture tool to get the request sent when checking in, then use Python’s requests module to simulate that request. Actually, I had this idea back when I just started my master’s degree, but at that time I was stuck on the first step below. 😅

Capturing HTTPS with Fiddler

My coding ability is mediocre, and I don’t know much about network programming, so I don’t know whether all WeChat mini programs use the HTTPS protocol. The XinYangBuXi mini program of our college uses HTTPS. Back in my first year of grad school, I tried to capture packets with Fiddler but just couldn’t. It wasn’t until I saw the code provided by my classmate Vampirehh that I asked him why I couldn’t capture anything; he told me I needed to change a setting. So I opened Bing, searched, and found out that Fiddler doesn’t capture HTTPS by default and you need to configure it manually.

Open Fiddler, select Tools -> Options; in the Options tab, choose Https, and check Capture Https CONNECTs, Decrypt HTTPS traffic, and Ignore server certificate errors(unsafe). Finally click OK.

image-20211106175554372

image-20211106175702394

Start Capturing

Next, we can open the XinYangBuXi mini program and start capturing packets.

Log in to the mini program on PC.

image-20211106180333615

Fill in the basic information and click the submit button.

动画

Next, in the Fiddler interface we can see a request with response code 200 whose host is www.dmuistac.com. Click this request to view the details.

image-20211106183311155

From the details, we can actually check in just by visiting the original request in a browser.

image-20211106184905008

For example, I can check in by visiting the following URL. (Clicking it once helps me check in once 😁)

https://www.dmuisatc.com/DMU_WEB/student_5/info/?jsonnumber=1120200298&jsonname=汪广鑫&jsonclass=2020级硕士研究生中队&morning=36.4℃&afternoon=36.4℃&night=36.4℃&jsonbody=1&jsonbodychangeinfo=&textarea=在校&textprople=同学&jsontouch=1&jsontouchchangeinfo=0&jsonisolate=1&jsonisolatechangeinfo=0&latitude=38.91369&longitude=121.61476

This is how the URL is composed.

image-20211106185715185

The result of visiting it in a browser is shown below.

image-20211106185351851

To further prove that our browser visit can check in, we can click the My Reports button in the WeChat mini program to view the latest packets captured by Fiddler and see the time of the most recent check-in.

image-20211106190025042

You can see that the last report time today is exactly the time I just visited the URL in the browser.

image-20211106190220552

编写代码

接下来,我们就可以编写 python 代码,使用代码进行签到了。

Host 改变了

Writing the Code

Next, we can write a Python script to check in with code.

The Host has changed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests

url = "https://www.dmuisatc.com/DMU_WEB/student_5/info/?jsonnumber=112020028&jsonname=%E6%B1%AA%E5%B9%BF%E9%91%AB&jsonclass=2020%E7%BA%A7%E7%A1%95%E5%A3%AB%E7%A0%94%E7%A9%B6%E7%94%9F%E4%B8%AD%E9%98%9F&morning=36.4%E2%84%83&afternoon=36.4%E2%84%83&night=36.4%E2%84%83&jsonbody=1&jsonbodychangeinfo=&textarea=%E5%9C%A8%E6%A0%A1&textprople=%E5%90%8C%E5%AD%A6&jsontouch=1&jsontouchchangeinfo=0&jsonisolate=1&jsonisolatechangeinfo=0&latitude=38.91369&longitude=121.61476"

headers = {
'Host': 'www.dmuisatc.com',
'Connection': 'keep-alive',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat',
'content-type': 'application/json',
'Referer': 'https://servicewechat.com/wx8a86613d14cbe10c/12/page-frame.html',
'Accept-Encoding': 'gzip, deflate, br'
}

res = requests.get(url,headers=headers)

print(res.text)
print(res)

执行上面的代码即可完成你的签到。

image-20211106191211855

再次点击小程序的 我的填报,可以看到 FIddler 的最新抓包结果显示代码也确实实现成功签到了。

image-20211106192738656

Running the code above completes your check-in.

image-20211106191211855

Click My Reports in the mini program again, and the latest packets in Fiddler will show that the code did successfully check in.

image-20211106192738656

代码优化

上面的代码已经能够实现我们的基本需求,但是请求的链接是编码过的,看起来不是很友好。接下来我们写一个人看的版本。

首先我们依据 WebForms 编写字典,在利用 urlencode() 函数对字典进行 url 编码,最后请求编码后的 url 链接即可。

首先在 FIddler 中点击 WebForms,查看表单内容。

image-20211106194345600

将表单内容写成字典。

Code Optimization

The code above already meets our basic needs, but the request URL is encoded and doesn’t look friendly. Next, let’s write a human-readable version.

First, we write a dictionary based on WebForms, then use the urlencode() function to URL-encode the dictionary, and finally request the encoded URL.

First, click WebForms in Fiddler to view the form contents.

image-20211106194345600

Write the form contents as a dictionary.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import requests
from urllib.parse import urlencode

url = "https://www.dmuisatc.com/DMU_WEB/student_5/info/?"

headers = {
'Host': 'www.dmuisatc.com', ## 已经变了
'Connection': 'keep-alive',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat',
'content-type': 'application/json',
'Referer': 'https://servicewechat.com/wx8a86613d14cbe10c/12/page-frame.html',
'Accept-Encoding': 'gzip, deflate, br'
}

data = {
"jsonnumber": "1120200298",
"jsonname": "汪广鑫",
"jsonclass": "2020级硕士研究生中队",
"morning": "36.2℃",
"afternoon": "36.2℃",
"night": "36.2℃",
"jsonbody": 1,
"jsonbodychangeinfo": "",
"textarea": "学校",
"textprople": "同学",
"jsontouch": 1,
"jsontouchchangeinfo": 0,
"jsonisolate": 1,
"jsonisolatechangeinfo": 0,
"latitude": 38.8699, # 最后两个是经纬度
"longitude": 121.5276, # 可以通过谷歌地图获取想要定位位置的经纬度
}

res = requests.get(url+urlencode(data),headers=headers)

print(res.text)
print(res)

执行上面的代码,依然可以签到成功。

image-20211106195156659

最后,提供一个多人同时签到的版本,其实就是把 jsonnumber 和 jsonname 写成列表的形式。

Running the code above still checks in successfully.

image-20211106195156659

Finally, here’s a version that checks in for multiple people at once — it simply puts jsonnumber and jsonname in list form.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import requests
from urllib.parse import urlencode
import json
import time

headers = {
'Host': 'www.dmuisatc.com', ## 已经变了
'Connection': 'keep-alive',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat',
'content-type': 'application/json',
'Referer': 'https://servicewechat.com/wx8a86613d14cbe10c/10/page-frame.html',
'Accept-Encoding': 'gzip, deflate, br'
}

datas = []

id = ["学号1","学号2","学号3"]
name = ["姓名1","姓名2","姓名3"]

for i in range(len(id)):
datas.append({
"jsonnumber": id[i],
"jsonname": name[i],
"jsonclass": "2020级硕士研究生中队",
"morning": "36.2℃",
"afternoon": "36.2℃",
"night": "36.2℃",
"jsonbody": 1,
"jsonbodychangeinfo": "",
"textarea": "学校",
"textprople": "同学",
"jsontouch": 1,
"jsontouchchangeinfo": 0,
"jsonisolate": 1,
"jsonisolatechangeinfo": 0,
"latitude": 38.8699,
"longitude": 121.5276,
})

for j in range(len(id)):
url = 'https://www.dmuisatc.com/DMU_WEB/student_5/info/?'
url = url + urlencode(datas[j])
print(url)
daka = requests.get(url, headers=headers)
print(daka.text)
print(daka)
time.sleep(10)

基于 GitHub Actions 实现自动签到

如果你有网络服务器,可以把这个脚本放在服务器上执行定时任务,考虑到大多数人是没有服务器的,所以我们这里介绍如何利用GitHub Actions 实现自动签到。

我不会做科普工作,如果你不知道什么是 GitHub Actions 建议自行百度。这里只教你怎么做,一步一步跟着做就好了。

Automatic Check-in with GitHub Actions

If you have a web server, you can put this script on it as a scheduled task; since most people don’t have a server, we’ll introduce how to achieve automatic check-in with GitHub Actions.

I won’t explain what GitHub Actions is — if you don’t know, search for it yourself. I’ll just teach you how to do it, step by step.

首先,登录 GitHub,创建一个新的仓库。

image-20211107021356227

填写基本信息点击创建仓库。

image-20211107021517003

创建 python 文件并粘贴已经写好的代码。

动画

同样的步骤再创建一个执行代码所需要的环境文件,requirements.txt

image-20211107022251748

接下来创建 GitHub Actions 的配置文件。

image-20211107022814602

First, log in to GitHub and create a new repository.

image-20211107021356227

Fill in the basic information and click create repository.

image-20211107021517003

Create a Python file and paste the code we’ve already written.

动画

With the same steps, create an environment file required to run the code: requirements.txt.

image-20211107022251748

Next, create the GitHub Actions configuration file.

image-20211107022814602

The file contents are as follows:

文件的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

name: XinYangBuXi

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
watch:
types: started
schedule:
- cron: "0 */8 * * *"

jobs:
XinYangBuXi:
runs-on: ubuntu-latest

steps:
- name: 'Checkout codes'
uses: actions/checkout@v2

- name: 'setup python'
uses: actions/setup-python@master
with:
python-version: 3.7

- name: 'requirements'
run: |
pip3 install -r requirements.txt

- name: '打卡'
run: |
python daka.py
echo `date +"%Y-%m-%d %H+8:%M:%S"` begin > time.log

- name: 'Commit Files'
id: commit
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add .
git diff --quiet && git diff --staged --quiet || git commit -am 'avoid being suspended'
echo ::set-output name=status::success

- name: 'GitHub Push'
if: steps.commit.output.status != 'success'
uses: ad-m/github-push-action@v0.6.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}

接下来点击 Actions 可以看到一个已经运行的工作流。如果你是第一次使用 GitHub Actions 可能还需要点几个 Enable ,自己看情况操作就行了。如果你看到了下图画面,就表示代码已经成功运行了。

image-20211107023438506

我们点击查看具体运行情况。

image-20211107023533276

可以看到确实打卡成功了✨

image-20211107023633178

我们的仓库里会多一个 time.log 文件,里面记录着上一次执行代码的时间。

image-20211107023737836

至此,Fuck 信仰不息的工作就已经完成了。我们以后再也不需要抱歉了。

Next, click Actions and you’ll see a workflow that has already run. If this is your first time using GitHub Actions, you may need to click Enable a few times — just handle it as needed. If you see the screen below, the code has run successfully.

image-20211107023438506

Click it to view the details of the run.

image-20211107023533276

You can see the check-in did succeed ✨

image-20211107023633178

There will be an extra time.log file in our repository, recording the time the code last ran.

image-20211107023737836

At this point, the work of Fuck XinYangBuXi is complete. We never need to apologize again.

打卡提醒

使用 SMTP 服务可以收到邮件提醒,SMTP 服务我觉得国内的 QQ 邮箱和 163 邮箱都挺好用的,由于我不想每天都收到邮件提醒,就不写相关代码了。有兴趣的自行百度吧,毕竟我也是面向百度程序设计的。

使用 Qmsg 的服务可以实现 QQ 提醒。

类似地,使用 Server酱 的服务可以实现微信提醒。

我嫌弃这些提醒太烦人了,我选择使用 Telegram Bot 进行提醒,其实不叫提醒,因为我手机的 Telegram 不会主动推送消息,可能是代理服务器不太好用的原因吧,我只是需要一个记录程序执行结果的地方,我想主动查看的时候不必去 GitHub,看一眼手机就可以了。

在你已经申请好 Telegram Bot 并且已知自己 chat ID 的情况下,只需加入以下几行代码就可以完成推送了。

Check-in Reminders

Using the SMTP service, you can get email reminders. For SMTP, I think QQ Mail and 163 Mail work well; since I don’t want email reminders every day, I won’t write the related code. If you’re interested, search for it yourself — after all, I also program by searching everything up.

Using the Qmsg service, you can get QQ reminders.

Similarly, using the Server酱 service, you can get WeChat reminders.

I find these reminders too annoying, so I chose to use a Telegram Bot for notifications. Actually, it’s not really a notification, because Telegram on my phone doesn’t push messages proactively — maybe my proxy server isn’t great. I just need a place to record the execution results of the program, so when I want to check, I don’t have to go to GitHub; a glance at my phone is enough.

Provided you’ve already applied for a Telegram Bot and know your chat ID, just add the following lines of code to complete the push notification.

1
2
3
4
5
6
7
import telebot # 你需要在你的 requirements.txt 文件中加入 pyTelegramBotAPI

chat_id = ""
token = ""
bot = telebot.TeleBot(token)

bot.send_message(chat_id=chat_id,text=str(daka)+'\n'+str(daka.text) + '\n\n')

推送结果:

F95366DDD073A928F4BA86C79ABE4E71

最后,请注意,如果你和我一样,只会面向百度程序设计,把所有变量都写死。换句话说,如果你的脚本里暴漏了你的 SMTP 密码或者 Qmsg Token 或者 Server酱 Token 或者 Telegram Bot 的 Token,那么你应该把你的仓库设置成私有的,以防止恶作剧者利用这些对你进行骚扰,甚至是进行违法行为!

Push result:

F95366DDD073A928F4BA86C79ABE4E71

Finally, please note: if, like me, you can only program by searching everything up and hardcode all variables — in other words, if your script leaks your SMTP password, Qmsg Token, Server酱 Token, or Telegram Bot Token — then you should set your repository to private, to prevent pranksters from using them to harass you, or even commit illegal acts!

必看的更新内容

2021 年 11 月 16 日

信仰不息的 Host 改变了

image-20211116180202087

所以现在应该 get 请求 www.informationofdum.com 这个地址了。

代码更新为:

Must-Read Updates

November 16, 2021

The Host of XinYangBuXi has changed

image-20211116180202087

So now you should GET the address www.informationofdum.com.

The code has been updated to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import requests
from urllib.parse import urlencode
import json
import time

headers = {
'Host': 'www.informationofdum.com',
'Connection': 'keep-alive',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat',
'content-type': 'application/json',
'Referer': 'https://servicewechat.com/wx8a86613d14cbe10c/13/page-frame.html',
'Accept-Encoding': 'gzip, deflate, br'
}

datas = []

id = ["学号1","学号2","学号3"]
name = ["姓名1","姓名2","姓名3"]

for i in range(len(id)):
datas.append({
"jsonnumber": id[i],
"jsonname": name[i],
"jsonclass": "2020级硕士研究生中队",
"morning": "36.2℃",
"afternoon": "36.2℃",
"night": "36.2℃",
"jsonbody": 1,
"jsonbodychangeinfo": "",
"textarea": "学校",
"textprople": "同学",
"jsontouch": 1,
"jsontouchchangeinfo": 0,
"jsonisolate": 1,
"jsonisolatechangeinfo": 0,
"latitude": 38.8699,
"longitude": 121.5276,
})

for j in range(len(id)):
url = 'https://www.informationofdum.com/DMU_WEB/student_5/info/?'
url = url + urlencode(datas[j])
print(url)
daka = requests.get(url, headers=headers)
print(daka.text)
print(daka)
time.sleep(10)