cherry reborn!!!

This commit is contained in:
ElonLi 2021-09-04 10:50:46 +08:00
parent ae6fe3ee8f
commit b660dd033c
8 changed files with 133 additions and 80 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
__pycache__ __pycache__
.vscode/settings.json .vscode/settings.json
venv venv

View File

@ -8,13 +8,6 @@ python3 -m venv venv
. venv/bin/activate . venv/bin/activate
// 升级pip // 升级pip
pip install --upgrade pip pip install --upgrade pip
// 安装flask...
pip install Flask
pip install requests
pip install bs4
pip install gunicorn
pip install pymongo
pip install flask_cors
// 根据依赖文件安装环境 // 根据依赖文件安装环境
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
// 设置全局变量 // 设置全局变量

View File

@ -2,7 +2,7 @@
import sys import sys
sys.path.append('./lib') sys.path.append('./lib')
# 引入处理函数 # 引入处理函数
from allFunction import manageLogin, manageScheduleUpload, manageScheduleGet from allFunction import manageLogin, manageScheduleUpload, manageScheduleGet, manageSubmitVerificationCode
# 引入flask # 引入flask
from flask import Flask, request, session, redirect from flask import Flask, request, session, redirect
# 初始化app # 初始化app
@ -24,6 +24,11 @@ def login():
res = manageLogin(request) res = manageLogin(request)
return res return res
@app.route('/api/submitVC', methods=['POST'])
def submitVC():
res = manageSubmitVerificationCode(request)
return res
# 更新课表游戏排名信息 # 更新课表游戏排名信息
@app.route('/api/game/schedule/upload',methods=['POST']) @app.route('/api/game/schedule/upload',methods=['POST'])
def schedule_upload(): def schedule_upload():
@ -43,4 +48,4 @@ def miss(e):
# 本地运行启动 # 本地运行启动
if __name__ == '__main__': if __name__ == '__main__':
app.run(host="0.0.0.0", debug=True, port="80") app.run(host="127.0.0.1", debug=True, port="7980")

View File

@ -1,11 +1,16 @@
# coding=utf-8 # coding=utf-8
import sys
from requests.sessions import session
sys.path.append('./lib/public')
from crawler import Crawler from crawler import Crawler
import json import json
from hashlib import md5 from hashlib import md5
from urllib.parse import urlencode, unquote_plus from urllib.parse import urlencode, unquote_plus
from db import addRank, getRank from db import insertRank, findRank
# 主函数 # 主函数
crawlerCache = {}
# 处理登录操作 data:{cid,pwd,sign} # 处理登录操作 data:{cid,pwd,sign}
# 这里三个接口公用一个session所以合并成一个接口一个session走到底一次性返回所有数据 # 这里三个接口公用一个session所以合并成一个接口一个session走到底一次性返回所有数据
def manageLogin(request): def manageLogin(request):
@ -14,16 +19,26 @@ def manageLogin(request):
# MD5校验 # MD5校验
checked = checkData(data) checked = checkData(data)
if checked: if checked:
# 创建会话 c = Crawler()
phone = '' c.defaultInit(data)
if data.get('phone'):
phone = data['phone']
c = Crawler(data['cid'], data['pwd'], phone)
res = c.connection() res = c.connection()
crawlerCache[data['cid']] = c
return res
else:
return '数据校验失败', 400
def manageSubmitVerificationCode(request):
data = json.loads(request.form['data'])
checked = checkData(data)
if checked:
c = crawlerCache[data['cid']]
res = c.submitVerificationCode(data)
if res[-1] == 200: if res[-1] == 200:
c.getGrade() grade = c.getGrade()
c.getSchedule() ownSchedule = c.getOwnSchedule()
return c.getData() crawlerCache[data['cid']] = None
return json.dumps({'grade': grade, 'ownSchedule': ownSchedule}), 200
else: else:
return res return res
else: else:
@ -37,7 +52,7 @@ def manageScheduleUpload(request):
checked = checkData(data_cache) checked = checkData(data_cache)
data_cache.pop('sign') data_cache.pop('sign')
if checked: if checked:
add_res = addRank( data_cache['nick'], data_cache['count'], data_cache['time']) add_res = insertRank( data_cache['cid'], data_cache['nick'], data_cache['count'], data_cache['time'])
return add_res return add_res
else: else:
return '数据校验失败', 400 return '数据校验失败', 400
@ -51,7 +66,7 @@ def manageScheduleGet(request):
data_cache.pop('sign') data_cache.pop('sign')
if checked: if checked:
# 获取排名表 # 获取排名表
get_res = getRank() get_res = findRank()
return get_res return get_res
else: else:
return '数据校验失败', 400 return '数据校验失败', 400

View File

@ -78,7 +78,7 @@ def manageCrawler(cid, pwd, phone):
return get_res return get_res
grade = get_res[0] grade = get_res[0]
return { return {
'user_info': init_res[0] 'user_info': init_res[0],
'grade': grade, 'grade': grade,
'schedule': schedule, 'schedule': schedule,
}, 200 }, 200

View File

@ -1,21 +1,27 @@
import json import json
from json.encoder import JSONEncoder
import requests import requests
from urllib.parse import quote from urllib.parse import quote
import base64 import base64
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import random import random
import sys import sys
from werkzeug.utils import redirect
from utils import btoa, signCode from utils import btoa, signCode
from ocr import getCaptcha
class Crawler(object): class Crawler(object):
def __init__(self): def __init__(self):
self.__session = None self.__session = requests.Session()
self.__response = None
self.__pwd = None self.__pwd = None
self.__phone = None self.__phone = None
self.cid = None self.cid = None
self.sid = None self.sid = None
self.uid = None self.uid = None
self.real_name = None self.real_name = None
self.baseUrl = None
# 获取用户基本信息 # 获取用户基本信息
def getUserInfo(self): def getUserInfo(self):
@ -32,70 +38,82 @@ class Crawler(object):
try: try:
# 获取统一身份系统的网页 # 获取统一身份系统的网页
r = self.__session.get( r = self.__session.get(
url='https://mysso.cust.edu.cn/cas/login?service=https://jwgls1.cust.edu.cn/welcome') url='https://mysso.cust.edu.cn/cas/login?service=https://jwgl.cust.edu.cn/welcome')
soup = BeautifulSoup(r.text, 'html.parser') soup = BeautifulSoup(r.text, 'html.parser')
execution = soup.find_all(name='input')[6]['value'] execution = soup.find_all(name='input')[3]['value']
r = self.__session.get('https://mysso.cust.edu.cn/cas/captcha')
formdata = { formdata = {
'username': self.cid, 'username': self.cid,
'password': self.__pwd, 'password': self.__pwd,
'execution': execution, 'execution': execution,
'captcha': getCaptcha(r.content),
'_eventId': 'submit', '_eventId': 'submit',
'geolocation': '' 'geolocation': ''
} }
r = self.__session.post( r = self.__session.post(
url='https://mysso.cust.edu.cn/cas/login?service=https://jwgls1.cust.edu.cn/welcome', data=formdata) url='https://mysso.cust.edu.cn/cas/login?service=https://jwgl.cust.edu.cn/welcome', data = formdata)
soup = BeautifulSoup(r.text, 'html.parser') soup = BeautifulSoup(r.text, 'html.parser')
flag = soup.find(name='title') loginSuccess = (soup.find(name='title').text != "统一身份认证系统")
if(flag.text == "手机号设置"): self.__response = r
if self.__phone == '': if not loginSuccess:
return '请填写手机号', 513
execution = soup.find_all(name='input')[1]['value']
formdata = {
'phone': self.__phone,
'execution': execution,
'_eventId': 'submit',
'submit': '提交'
}
r = self.__session.post(
url="https://mysso.cust.edu.cn/cas/login?service=https://jwgls1.cust.edu.cn/welcome", data=formdata)
r = self.__session.get(
url='https://portal.cust.edu.cn/custp/index')
soup = BeautifulSoup(r.text, 'html.parser')
try:
if soup.findAll(name='a')[4]['href'] != 'logout':
raise('账号或密码错误')
except:
return '账号或者密码错误', 511 return '账号或者密码错误', 511
r = self.__session.get( return '登录成功', 200
url='https://mysso.cust.edu.cn/cas/login?service=https://jwgls1.cust.edu.cn/welcome', allow_redirects=False) except Exception as e:
ticket = r.headers['Location'][42:] print(e)
asp_net_sessionid_param = { return '教务挂了', 515
'Ticket': ticket, 'Url': 'https://jwgls1.cust.edu.cn/welcome'}
asp_net_sessionid_param = base64.b64encode( def submitVerificationCode(self, data):
quote(json.dumps(asp_net_sessionid_param)).encode('utf-8')).decode('utf-8') try:
asp_net_sessionid_param = {'param': asp_net_sessionid_param} r = self.__response
headers = {'Content-Type': 'application/json'} soup = BeautifulSoup(r.text, 'html.parser')
r = self.__session.post(url='https://jwgls1.cust.edu.cn/api/LoginApi/LGSSOLocalLogin?sf_request_type=ajax', execution = soup.find_all(name='input')[2]['value']
data=json.dumps(asp_net_sessionid_param), headers=headers) formdata = {
data = json.loads(r.content.decode('utf-8')) 'yzm': data['vc'],
# 提示未建立教务信息 'msgType': '',
if data['state'] == 1: 'execution': execution,
return data['message'], 514 '_eventId': 'submit'
self.real_name = data['data']['StudentDto']['XM'] }
self.sid = data['data']['StudentDto']['XH'] r = self.__session.post(
self.uid = data['data']['StudentDto']['SMXSJBXXID'] url = "https://mysso.cust.edu.cn/cas/login?service=https://jwgl.cust.edu.cn/welcome", data = formdata, allow_redirects = True)
return self.getUserInfo(), 200 self.__response = r
return 'gotcha!', 200
except Exception as e: except Exception as e:
print(e) print(e)
return '教务挂了', 515 return '教务挂了', 515
# 获取成绩 ----------------------------------------------------------------------------- # 获取成绩 -----------------------------------------------------------------------------
def getGrade(self): def getGrade(self):
r = self.__response
urlBase = r.url.split('.')[0]
ticket = r.url.split('?')[-1]
param = base64.b64encode(quote(json.dumps({
"Ticket":ticket.split('=')[-1],
"Url":"https://jwgl.cust.edu.cn/welcome"
})).encode('utf-8'))
self.baseUrl = urlBase
r = self.__session.post(
url = urlBase + '.cust.edu.cn/api/LoginApi/LGSSOLocalLogin',
data = {
"param": param,
"__log": {},
"__permission": {}
})
headers = {'Content-Type': 'application/json'} headers = {'Content-Type': 'application/json'}
r = self.__session.post( r = self.__session.post(
url='https://jwgls1.cust.edu.cn/api/ClientStudent/QueryService/GradeQueryApi/GetDataByStudent?sf_request_type=ajax', url=urlBase + '.cust.edu.cn/api/ClientStudent/QueryService/GradeQueryApi/GetDataByStudent',
data=json.dumps({"param": "JTdCJTIyU2hvd0dyYWRlVHlwZSUyMiUzQTElN0Q=", "__permission": {"MenuID": "4443798E-EB6E-4D88-BFBD-BB0A76FF6BD5", data=json.dumps({
"Operation": 0}, "__log": {"MenuID": "4443798E-EB6E-4D88-BFBD-BB0A76FF6BD5", "Logtype": 6, "Context": "查询"}}), "param": "JTdCJTIyU2hvd0dyYWRlVHlwZSUyMiUzQTAlN0Q=",
"__permission": {
"MenuID": "4443798E-EB6E-4D88-BFBD-BB0A76FF6BD5",
"Operate": "select",
"Operation": 0
},
"__log": {
"MenuID": "4443798E-EB6E-4D88-BFBD-BB0A76FF6BD5",
"Logtype": 6,
"Context": "查询"
}
}),
headers=headers headers=headers
) )
data = json.loads(r.content.decode('utf-8')) data = json.loads(r.content.decode('utf-8'))
@ -320,9 +338,20 @@ class Crawler(object):
def getOwnSchedule(self): def getOwnSchedule(self):
headers = {'Content-Type': 'application/json'} headers = {'Content-Type': 'application/json'}
r = self.__session.post( r = self.__session.post(
url='https://jwgls1.cust.edu.cn/api/ClientStudent/Home/StudentHomeApi/QueryStudentScheduleData?sf_request_type=ajax', url=self.baseUrl + '.cust.edu.cn/api/ClientStudent/Home/StudentHomeApi/QueryStudentScheduleData',
data=json.dumps({"param": "JTdCJTdE", "__permission": {"MenuID": "F71C97D5-D3E2-4FDA-9209-D7FA8626390E", data=json.dumps({
"Operation": 0}, "__log": {"MenuID": "F71C97D5-D3E2-4FDA-9209-D7FA8626390E", "Logtype": 6, "Context": "查询"}}), "param": "JTdCJTdE",
"__permission": {
"MenuID": "00000000-0000-0000-0000-000000000000",
"Operate": "select",
"Operation": "0"
},
"__log": {
"MenuID": "00000000-0000-0000-0000-000000000000",
"Logtype": 6,
"Context": "查询"
}
}),
headers=headers headers=headers
) )
data = json.loads(r.content.decode('utf-8')) data = json.loads(r.content.decode('utf-8'))
@ -336,7 +365,7 @@ class Crawler(object):
params = {"KBLX":"2","CXLX":"0","XNXQ":"20202","CXID":self.uid,"CXZC":"0","JXBLX":""} params = {"KBLX":"2","CXLX":"0","XNXQ":"20202","CXID":self.uid,"CXZC":"0","JXBLX":""}
params = str(btoa(json.dumps(params)))[2:-1] params = str(btoa(json.dumps(params)))[2:-1]
r = self.__session.post( r = self.__session.post(
url='https://jwgls1.cust.edu.cn/api/ClientStudent/QueryService/OccupyQueryApi/QueryScheduleData?sf_request_type=ajax', url=self.baseUrl + '.cust.edu.cn/api/ClientStudent/QueryService/OccupyQueryApi/QueryScheduleData?sf_request_type=ajax',
data=json.dumps({"param": params, "__permission": {"MenuID": "F71C97D5-D3E2-4FDA-9209-D7FA8626390E", data=json.dumps({"param": params, "__permission": {"MenuID": "F71C97D5-D3E2-4FDA-9209-D7FA8626390E",
"Operation": 0}, "__log": {"MenuID": "F71C97D5-D3E2-4FDA-9209-D7FA8626390E", "Logtype": 6, "Context": "查询"}}), "Operation": 0}, "__log": {"MenuID": "F71C97D5-D3E2-4FDA-9209-D7FA8626390E", "Logtype": 6, "Context": "查询"}}),
headers=headers headers=headers
@ -357,12 +386,11 @@ class Crawler(object):
return 'OK', 200 return 'OK', 200
# 默认初始化 # 默认初始化
def defaultInit(self, cid, pwd, phone): def defaultInit(self, data):
self.cid = cid self.cid = data['cid']
self.__pwd = pwd self.__pwd = data['pwd']
self.__phone = phone self.__phone = data['phone']
self.__session = requests.Session() self.__session = requests.Session()
return self.connection()
# 使用我的cookie初始化用于快速刷新课表 # 使用我的cookie初始化用于快速刷新课表
def cookieInit(self, cookies, uid, cid, sid, real_name): def cookieInit(self, cookies, uid, cid, sid, real_name):

View File

@ -154,7 +154,7 @@ def updateBg(cid, img_id):
用户更新背景图片 用户更新背景图片
""" """
try: try:
col('user').update('cid': cid, {'$set': {'setting.bg': img_id}}) col('user').update({'cid': cid}, {'$set': {'setting.bg': img_id}})
return 'OK', 200 return 'OK', 200
except Exception as e: except Exception as e:
print(e) print(e)
@ -305,7 +305,7 @@ def userInsertAllCrouse(crouses):
print(e) print(e)
return '用户所有课程数据库插入失败', 108 return '用户所有课程数据库插入失败', 108
def insertRank(nick, count, time): def insertRank(cid, nick, count, time):
""" """
向排名表里增加或者覆写数据 向排名表里增加或者覆写数据
""" """
@ -345,7 +345,7 @@ def findUserCrouse(sid):
return crouse_list, 200 return crouse_list, 200
except Exception as e: except Exception as e:
print(e) print(e)
reutrn '用户课程数据库查询失败', 304 return '用户课程数据库查询失败', 304
def groupInsertCrouse(crouse): def groupInsertCrouse(crouse):
""" """

12
lib/public/ocr.py Normal file
View File

@ -0,0 +1,12 @@
from aip import AipOcr
APP_ID = '24797034'
API_KEY = 'ykebbHq8GaK2cD1sIPy7PEPu'
SECRET_KEY = '4rU7QPC1oGFbZgIbsDvMGcqPky4kv7kV'
import base64
from urllib.parse import quote
import json
client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
def getCaptcha(image):
return client.numbers(image)['words_result'][0]['words']