每日获取强智教务系统课表,并发送短信到学生手机!爬虫真牛逼

自从学校换了强智的教务系统后 , 学校的app的查课表功能基本就报废了 , 记不住课表的我无奈自己动手 。
功能实现:如果当天有课 , 在当天早上6点30以短信的形式自动发送课表至手机
首先我想的是利用模拟登陆然后直接获取课表
输入一些错误信息 , 点击登陆 , 得到一个请求
每日获取强智教务系统课表,并发送短信到学生手机!爬虫真牛逼文章插图
其中的flag参数是重要线索 , 顺着这个参数找到对应的js
每日获取强智教务系统课表,并发送短信到学生手机!爬虫真牛逼文章插图
此时可以发现整个加密的流程
每日获取强智教务系统课表,并发送短信到学生手机!爬虫真牛逼文章插图
通过向/Logon.do?method=logon --tt-darkmode-color: #999999;">再将dataStr切片 , 分成scode与sxh
code = 用户名 + ‘%%%’ +密码
再通过for循环加密 , 得到encoded (登录的请求参数之一)
同时对验证码进行识别(我用的是pytesseract + PIL)
最后将userAccount(用户名)、userPassword(密码)、RANDOMCODE(验证码)、encoded作为参数向发起请求 , 即可完成模拟登录 。
但由于pytesseract的处理能力实在有限 , 识图率太低了(灰度处理、二值化、降噪后处理成功率还不到一半)
然后我选择了另一种方法强智有一个小程序叫智校园助手 , 利用HttpCanary可以获取强智的接口 , 然后又在git上找到了教务系统api的python封装
嘻嘻嘻 , 于是事情变得简单了起来
【每日获取强智教务系统课表,并发送短信到学生手机!爬虫真牛逼】import timeimport requestsimport reimport osimport jsonimport datetime #调用腾讯云api(pip install -i--upgrade tencentcloud-sdk-python 。 ) from tencentcloud.common import credentialfrom tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKExceptionfrom tencentcloud.sms.v20190711 import sms_client, modelsfrom tencentcloud.common.profile.client_profile import ClientProfilefrom tencentcloud.common.profile.http_profile import HttpProfileaccount = ""#此处为你的学号password = ""#此处为密码url = ""+"app/"#此处你自己学校教务系统ip地址 , 这里以湖南工大为例class SW(object):def __init__(self, account, password, url):super(SW, self).__init__()self.url = urlself.account = accountself.password = passwordself.session = self.login()#保持会话HEADERS = {"User-Agent": "Mozilla/5.0 (Linux; U; Mobile; Android 6.0.1;C107-9 Build/FRF91 )","Referer": "","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']#请求头中添加tokenreturn sessiondef 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.textdef 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]) - 1if 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 = Trueif iswork:rb = requests.get('株洲')#天气查询data = http://kandian.youth.cn/index/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 = kechennumber7 = shi_jiannumber8 = di_dian#此处8个参数用于传递给短信模版try:cred = credential.Credential("secretId", "secretKey")# 实例化一个认证对象 , 入参需要传入腾讯云账户密钥对secretId , secretKeyhttpProfile = HttpProfile()clientProfile = ClientProfile()clientProfile.language = "en-US"clientProfile.httpProfile = httpProfileclient = sms_client.SmsClient(cred, "ap-guangzhou", clientProfile)req = models.SendSmsRequest()req.SmsSdkAppid = ""#此处填写短信应用IDreq.Sign = ""#此处填写短信签名req.SenderId = ""req.PhoneNumberSet = ["+86",]#填入需要收到短信的号码req.TemplateID = ""#此处填写短讯模版idreq.TemplateParamSet =["{}".format(number1) ,"{}".format(number2),"{}".format(number3),"{}".format(number4),"{}".format(number5),"{}".format(number6),"{}".format(number7),"{}".format(number8)]resp = client.SendSms(req)#发送短信