【浙江|上海】青年大学习一键打卡

Github项目:https://github.com/lthero-big/ZheJiangYouthstudyAutoSign

特色

  • [x] 脚本一键运行,直接更新后台数据完成打卡:tada:
  • [x] 支持为多人批量打卡:thumbsup:
  • [x] 支持各平台服务器部署,可设置定时打卡任务:heavy_check_mark:

更新内容

2024.3.28更新: 感谢用户@b3nguang,新增功能:返回打卡完成的截屏图片的URL

截止到2024.3.28,脚本依可用

2023.3.12更新: 感谢吾爱用户:ahov 提供上海大学习接口,具体请查看原帖

目前已经添加上海青年大学习打卡脚本:ShangHaiAuto.py

代码思路:

  • 每个微信账号有唯一的openid
  • 在每次打开青年大学习网页时,后台会根据openid生成accessToken
  • 后续的所有与服务器交互的信息,都需要用accessToken才能拿到
  • 只要拿到个人信息,再将个人信息和accessToken提交即可打卡完成

使用

运行代码前,需要先获得openid,每个账号只要获得一次openid即可,以后无需重复抓包

PC获得openid教程【推荐】

视频教程:https://wwd.lanzouy.com/isVnb0cc5jba 密码:bcg5

  • 需要的软件:Fiddler、电脑版微信
  • 打开Fiddler,安装证书
  • 切换到微信,点击大学习,此时弹窗需要授权,点击“同意”。
  • 点击“同意”后,切换到Fiddler,按“ctrl+f”,搜索openid,双击标黄处的包,并点击“WebForms”,在里面找到openid即可
  • 注意:记录openId,因为以后没必要再次抓包!!!

安卓获得openId流程【部分手机无法用】

视频教程:https://wwd.lanzouy.com/isVnb0cc5jba 密码:bcg5

  • 安卓下载抓包软件 httpcanary,安装并打开软件,有三步骤:1、同意条款 2、允许安装证书 3、root可以跳过
  • 微信:打开大学习
  • 软件httpcanary:点击右下角小飞机图标开始抓包
  • 微信:点击“立即参与”->点击“去学习”。随后切到httpcanary,再点击右下角小飞机图标停止抓包。
  • 软件httpcanary:点击右上角,找到“搜索”,直接搜索“openId”,注意:只要url是qczj.h5yunban.com的包。一般可以在包名为“qczj.h5yunban.com/qczj-youth-learning/cgi-bin/user-api/course/last-info”的响应中,找到openId
  • 注意:记录openId,因为以后没必要再次抓包!!!

运行代码

  • 需要自行安装re,json,ymal,requests库
  • 获得openid后,将openid填入config.yml,运行index.py即可。
  • config.yml里面的name用来标识不同的openid,无实际意义

部署到服务器

在服务器下载项目文件

1
wget https://github.com/lthero-big/ZheJiangYouthstudyAutoSign/archive/refs/heads/main.zip

解压文件

1
unzip main.zip

随后,使用vim或其它工具,填写好config.yml的信息

设置定时任务

填写好config.yml后,使用crontab命令,设置定时执行的任务

方法一

使用输入命令crontab -e进行编辑定时任务,把下面这行添加到最后一行

注意修改/home/main/ZheJiangAuto.py为实际文件路径

1
30 15 * * 3  python /home/main/ZheJiangAuto.py >> /home/main/autosign.log 2>&1

每周三15点30分执行一次打卡任务,并且将打卡脚本输出的内容放在/home/autosign.log

方法二

先创建一个shell文件,如放在/home/autosign.sh,填写下面的内容

注意:把/home/main/ZheJiangAuto.py修改成实际的项目路径,main目录下要有config.yml文件

1
2
3
4
5
6
7
8
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
python /home/main/ZheJiangAuto.py
echo "----------------------------------------------------------------------------"
endDate=`date +"%Y-%m-%d %H:%M:%S"`
echo "[$endDate]"
echo "----------------------------------------------------------------------------"

随后,给/home/autosign.sh添加执行权限

1
chmod +x /home/autosign.sh

使用输入命令crontab -e进行编辑定时任务,把下面这行添加到最后一行

1
30 15 * * 3  /home/autosign.sh >> /home/autosign.log 2>&1

每周三15点30分执行一次打卡任务,并且将打卡脚本输出的内容放在/home/autosign.log

邮件发送功能

  • 在config.yml配置好接收方邮箱
  • 有两个sendMail函数,第一个是使用发送邮件的api,第二个是使用python库发送,没有api的可以使用第二个函数
  • 在第二个sendMail中设置发送方邮箱信息【需要自行搜索“用QQ的SMTP发送邮件配置”】

注意

如果没有需要第2步授权步骤,而是直接进入大学习页面,则无法获得openid。

需要彻底关掉微信,并重新打开微信,再尝试。

无论手机端或电脑端,如果实现得不到openid,需要点击“开始学习”进入到选择省市的选项。

再切到Fiddler或httpcanary,按“ctrl+f”,搜索accessToken。得到accessToken后,

比如accessToken为xxxx-xxxx-xxxx-xxxx,将其合并到下面的链接

https://qczj.h5yunban.com/qczj-youth-learning/cgi-bin/user-api/info?accessToken=xxxx-xxxx-xxxx-xxxx

替换上面的xxxx-xxxx-xxxx-xxxx。

随后进行访问此链接,可以在返回的结果里面找到openid


文件:config.yml

1
2
3
4
5
6
7
users:
- user:
name: '张三'
openid: 'oO-a2tabkGObaWbIOd4U1Bpaf1l0'
- user:
name: '李四'
openid: 'oO-a2t7bkGhdaWbIOd4U1Bpaf1l0'


文件:index.py

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import re
import requests
import json
import yaml

getToken_url = 'https://qczj.h5yunban.com/qczj-youth-learning/cgi-bin/login/we-chat/callback'
getUserInfo_url = 'https://qczj.h5yunban.com/qczj-youth-learning/cgi-bin/user-api/course/last-info'
getClass_url = 'https://qczj.h5yunban.com/qczj-youth-learning/cgi-bin/common-api/course/current'
checkin_url = 'https://qczj.h5yunban.com/qczj-youth-learning/cgi-bin/user-api/course/join'

headers = {
'Content-Type': 'text/plain'
}


def getYmlConfig(yaml_file='config.yml'):
with open(yaml_file, 'r', encoding='utf-8') as f:
file_data = f.read()
return dict(yaml.load(file_data, Loader=yaml.FullLoader))


def getToken(openId):
# 根据openId获得token
try:
getToken = requests.get(url=getToken_url, params=openId, headers=headers)
Token_raw = getToken.text
Token = re.findall('[A-Z0-9]{8}[-][A-Z0-9]{4}[-][A-Z0-9]{4}[-][A-Z0-9]{4}[-][A-Z0-9]{12}', Token_raw)[0]
print('获取Token为:' + Token)
except:
print('获取Token失败,请检查openId是否正确')
accessToken = {
'accessToken': Token
}
return accessToken


def getinfo(accessToken):
# 根据accessToken获得用户信息
try:
getUserInfo = requests.get(getUserInfo_url, params=accessToken, headers=headers)
userInfo = getUserInfo.json()
cardNo = userInfo["result"]["cardNo"]
nid = userInfo["result"]["nid"]
getClass = requests.get(getClass_url, params=accessToken, headers=headers)
Class = getClass.json()
classId = Class["result"]["id"]
infos: list = userInfo['result']['nodes']
Faculty = [item['title'] for item in infos]
print('签到课程为:' + classId, '\n您填写的个人信息为:' + cardNo, '\n您的签到所属组织为:' + str(Faculty))
except Exception as e:
print(f'获取历史信息失败,请您手动打卡:{e}')

checkinData = {
'course': classId,
'subOrg': None,
'nid': nid,
'cardNo': cardNo
}
return checkinData


def signup(accessToken, checkinData):
# 根据token和data完成打卡
checkin = requests.post(checkin_url, params=accessToken, data=json.dumps(checkinData), headers=headers)
result = checkin.json()

if result["status"] == 200:
print("签到成功")
else:
print('出现错误,错误码:' + result["status"])
print('错误信息:' + result["message"])


if __name__ == "__main__":
config = getYmlConfig()
for index, user in enumerate(config['users']):
print(user['user']['name'], 'openId为 ', user['user']['openid'])
openid = {
'appid': 'wx56b888a1409a2920',
'openid': user['user']['openid']
}
accesstoken = getToken(openid)
checkindata = getinfo(accesstoken)
signup(accesstoken, checkindata)
print('===========================================')

最后,使用定时任务crontab即可。