自从学校换了强智的教务系统后,学校的app的查课表功能基本就报废了,记不住课表的我无奈自己动手。
功能实现:如果当天有课,在当天早上6点30以短信的形式自动发送课表至手机
首先我想的是利用模拟登陆然后直接获取课表
输入一些错误信息,点击登陆,得到一个请求
其中的flag参数是重要线索,顺着这个参数找到对应的js
此时可以发现整个加密的流程
通过向/Logon.do?method=logon&flag=sess发送请求获得一个dataStr
再将dataStr切片,分成scode与sxh
code = 用户名 + ‘%%%’ +密码
再通过for循环加密,得到encoded (登录的请求参数之一)
同时对验证码进行识别(我用的是pytesseract + PIL)
最后将userAccount(用户名)、userPassword(密码)、RANDOMCODE(验证码)、encoded作为参数向http://logon.do/?method=logon发起请求,即可完成模拟登录。
但由于pytesseract的处理能力实在有限,识图率太低了(灰度处理、二值化、降噪后处理成功率还不到一半)
然后我选择了另一种方法
强智有一个小程序叫智校园助手,利用HttpCanary可以获取强智的接口,然后又在git上找到了教务系统api的python封装
嘻嘻嘻,于是事情变得简单了起来
import time
import requests
import re
import os
import json
import datetime
#调用腾讯云api(pip install -i https://mirrors.tencent.com/pypi/simple/ --upgrade tencentcloud-sdk-python。)
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.sms.v20190711 import sms_client, models
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
account = "" #此处为你的学号
password = "" #此处为密码
url = "http://218.75.197.123:83/"+"app/" #此处你自己学校教务系统ip地址,这里以湖南工大为例
class SW(object):
def __init__(self, account, password, url):
super(SW, self).__init__()
self.url = url
self.account = account
self.password = password
self.session = self.login() #保持会话
HEADERS = {
"User-Agent": "Mozilla/5.0 (Linux; U; Mobile; Android 6.0.1;C107-9 Build/FRF91 )",
"Referer": "http://www.baidu.com",
"accept-encoding": "gzip, deflate, br",
"accept-language": "zh-CN,zh-TW;q=0.8,zh;q=0.6,en;q=0.4,ja;q=0.2",
"cache-control": "max-age=0"
}
def login(self):
params = {
"method": "authUser",
"xh": self.account,
"pwd": self.password
}
session = requests.Session()
req = session.get(self.url, params=params, timeout=5, headers=self.HEADERS)
s = json.loads(req.text)
# if s['flag'] != "1": exit(0)
self.HEADERS['token'] = s['token'] #请求头中添加token
return session
def get_current_time(self): #获取当前时间信息
params = {
"method": "getCurrentTime",
"currDate": datetime.datetime.now().strftime('%Y-%m-%d')
}
req = self.session.get(self.url, params=params, timeout=5, headers=self.HEADERS)
return req.text
def get_class_info(self, zc=-1): #获取课表
s = json.loads(self.get_current_time())
params = {
"method": "getKbcxAzc",
"xnxqid": s['xnxqh'],
"zc": s['zc'] if zc == -1 else zc,
"xh": self.account
}
req = self.session.get(self.url, params=params, timeout=5, headers=self.HEADERS)
return json.loads(req.text)
if __name__ == '__main__':
Q = SW(account, password, url)
information = Q.get_class_info() #当前周次课表
s_time = json.loads(Q.get_current_time())
year, month, day = s_time['s_time'].split("-",2) #将课表时间拆分成年月日
start = datetime.date(int(year), int(month), int(day))
now = datetime.date.today()
year, month, day = str(now).split("-", 2) #将当前时间拆分成年月日
kechen, shi_jian, di_dian ='', '',''
iswork =False #今天是否有课
#由于本人现在每天只有一节课,且由于我腾讯云验证为个人开发者,短信模版只允许12字变量,故以仅字符串保存变量。
如课程较多且为企业开发者,可以考虑直接将某节课的所有信息合成一个变量并存入列表中
for i in range(len(information)): #遍历课表
change_time = int(information[i]['kcsj'][0]) - 1
if now == start+datetime.timedelta(days=change_time): #判断今天是否有课
kechen = information[i]['kcmc'] #课程名
shi_jian = information[i]['kssj'] +"-"+ information[i]['jssj'] #课程时间
di_dian = information[i]['jsmc'] #上课地点
iswork = True
if iswork:
rb = requests.get('http://wthrcdn.etouch.cn/weather_mini?city=株洲') #天气查询
data = json.loads(rb.text)
number1 = year + "年" + month + "月" + day + "日"
number2 = s_time['zc']
number3 = data['data']['forecast'][0]['date'][2:]
number4 = data['data']['forecast'][0]['type']
number5 = data['data']['forecast'][0]['low'][2:] + "-" + data['data']['forecast'][0]['high'][2:]
number6 = kechen
number7 = shi_jian
number8 = di_dian
#此处8个参数用于传递给短信模版
try:
cred = credential.Credential("secretId", "secretKey")
# 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey
httpProfile = HttpProfile()
clientProfile = ClientProfile()
clientProfile.language = "en-US"
clientProfile.httpProfile = httpProfile
client = sms_client.SmsClient(cred, "ap-guangzhou", clientProfile)
req = models.SendSmsRequest()
req.SmsSdkAppid = "" #此处填写短信应用ID
req.Sign = "" #此处填写短信签名
req.SenderId = ""
req.PhoneNumberSet = ["+86",] #填入需要收到短信的号码
req.TemplateID = "" #此处填写短讯模版id
req.TemplateParamSet =["{}".format(number1) ,
"{}".format(number2),
"{}".format(number3),
"{}".format(number4),
"{}".format(number5),
"{}".format(number6),
"{}".format(number7),
"{}".format(number8)]
resp = client.SendSms(req) #发送短信
最后只需要在利用crontab在服务器上设置一个定时任务每天6点30执行一次就可以啦
30 6 * * * python /home/kechenbiao/kechenbiao.py
最终效果;
腾讯短信可以参考 https://github.com/TencentCloud/tencentcloud-sdk-
完整项目代码获取点这里即可