自从学校换了强智的教务系统后,学校的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-python/blob/master/examples/sms/v20190711/SendSms.py
(由于本人只需要课表,所以只做了课表查询,实际功能还有很多,包括成绩查询、空教室查询等)
神龙|纯净稳定代理IP免费测试>>>>>>>>天启|企业级代理IP免费测试>>>>>>>>IPIPGO|全球住宅代理IP免费测试