This commit is contained in:
RainSun 2020-01-18 00:58:47 +08:00
commit f303dcb755
5 changed files with 182 additions and 0 deletions

35
README.md Normal file
View File

@ -0,0 +1,35 @@
# 挂柯南
## 服务器配置
```js
// 安装venv
python3 -m venv venv
// 启动venv
. venv/bin/activate
// 升级pip
pip install --upgrade pip
// 安装flask...
pip install Flask
pip install requests
pip install bs4
pip install gunicorn
// 设置全局变量
export FLASK_APP=cust.py
export FLASK_ENV=development
// 启动临时服务
flask run --host=0.0.0.0 -p 5003
// 启动永久服务
gunicorn cust:app -c gunicorn.conf
// 查看已启动服务
pstree -ap|grep gunicorn
// 关闭某服务
kill (pid)
```
## 错误代码一览
/login
100数据校验失败
101账户错误
102教务挂了
200ok

18
cust.py Normal file
View File

@ -0,0 +1,18 @@
# 引入文件夹中的文件
import sys
sys.path.append('./lib')
from allFunction import manageLogin
from flask import Flask, request
app = Flask(__name__)
if __name__ == '__main__':
app.run()
# 登录接口前端提供cid和pwd包装在data里边然后md5校验也就是data:{cid,pwd,sign}
@app.route('/api/login',methods=['POST'])
def login():
res = manageLogin(request)
print(res)
return res

13
gunicorn.conf Normal file
View File

@ -0,0 +1,13 @@
# 并行工作线程数
workers = 4
# 监听内网端口5000【按需要更改】
bind = '127.0.0.1:5003'
# 设置守护进程【关闭连接时,程序仍在运行】
daemon = True
# 设置超时时间120s默认为30s。按自己的需求进行设置
timeout = 120
# 设置访问日志和错误信息日志路径
accesslog = './logs/acess.log'
errorlog = './logs/error.log'
#自动重启
autostart = True

45
lib/allFunction.py Normal file
View File

@ -0,0 +1,45 @@
from crawler import connection, getGrade, getTimetable
import json
# 主函数
# 处理登录操作 data:{cid,pwd,sign}
# 这里三个接口公用一个session所以合并成一个接口一个session走到底一次性返回所有数据
def manageLogin(request):
# josn化应该能当dist用
data_cache = json.loads(request.form['data'])
# MD5校验
checked = checkData(data_cache)
if checked:
# 创建会话
res = connect(data_cache)
if res['errcode'] == 200:
# 登录成功并进行查询
grade = getGrade(res['ip'], res['s'])
time_table = getTimetable(res['ip'], res['s'])
return {'errcode': '200', 'errmsg': 'ok', 'grade': grade, 'time_table': time_table}
else:
return res
else:
return {'errcode': 100, 'errmsg':'数据校验失败'}
# 工具函数
# MD5 校验
def checkData(data):
return True
# 创建会话
def connect(data):
# 用户id 2017....
cid = data['cid']
# 用户密码
pwd = data['pwd']
# 进行登录
try:
# 这里教务没问题账户没问题就是200密码错了就是101
res = connection(cid,pwd)
return res
except:
# 这了就是教务挂了
return {'errcode': 102, 'errmsg':'教务挂了'}

71
lib/crawler.py Normal file
View File

@ -0,0 +1,71 @@
import json
import requests
from urllib.parse import quote
import base64
from bs4 import BeautifulSoup
def connection(username,password):
s = requests.Session()
# 获取统一身份系统的网页
r = s.get(url='http://mysso-cust-edu-cn-s.webvpn.cust.edu.cn:8118/cas/login?service=https%3A%2F%2Fwebvpn.cust.edu.cn%2Fauth%2Fcas_validate%3Fentry_id%3D1')
soup = BeautifulSoup(r.text,'lxml')
execution=soup.find_all(name='input')[6]['value']
formdata={
'username':username,
'password':password,
'execution':execution,
'_eventId':'submit',
'geolocation':''
}
r = s.post(url='http://mysso-cust-edu-cn-s.webvpn.cust.edu.cn:8118/cas/login?service=https%3A%2F%2Fwebvpn.cust.edu.cn%2Fauth%2Fcas_validate%3Fentry_id%3D1',data=formdata)
r = s.get(url='http://portal-cust-edu-cn-s.webvpn.cust.edu.cn:8118/custp/index')
soup=BeautifulSoup(r.text,'html.parser')
try:
ip = soup.findAll(name='a')[6]['href'][7:].split("-")
except:
return {'errcode': 101, 'errmsg':'账号或者密码错误'}
r = s.get(url='http://mysso-cust-edu-cn-s.webvpn.cust.edu.cn:8118/cas/login?service=http://'+ip[0]+'.'+ip[1]+'.'+ip[2]+'.'+ip[3]+':8080/welcome',allow_redirects=False)
ticket = r.headers['Location'][68:]
asp_net_sessionid_param = {'Ticket':ticket,'Url':'http://'+ip[0]+'.'+ip[1]+'.'+ip[2]+'.'+ip[3]+':8080/welcome'}
asp_net_sessionid_param = base64.b64encode(quote(json.dumps(asp_net_sessionid_param)).encode('utf-8')).decode('utf-8')
asp_net_sessionid_param = {'param':asp_net_sessionid_param}
headers = {'Content-Type': 'application/json'}
r = s.post(url='http://'+ip[0]+'-'+ip[1]+'-'+ip[2]+'-'+ip[3]+'-8080-p.webvpn.cust.edu.cn:8118/api/LoginApi/LGSSOLocalLogin?sf_request_type=ajax',data=json.dumps(asp_net_sessionid_param),headers=headers)
return {'errcode': 200, 'errmsg': 'ok', 'ip': ip, 's': s}
def getGrade(Ip, S):
headers = {'Content-Type': 'application/json'}
r = S.post(
url='http://'+Ip[0]+'-'+Ip[1]+'-'+Ip[2]+'-'+Ip[3]+'-8080-p.webvpn.cust.edu.cn:8118/api/ClientStudent/QueryService/GradeQueryApi/GetDataByStudent?sf_request_type=ajax',
data=json.dumps({"param":"JTdCJTIyU2hvd0dyYWRlVHlwZSUyMiUzQTElN0Q=","__permission":{"MenuID":"4443798E-EB6E-4D88-BFBD-BB0A76FF6BD5","Operation":0},"__log":{"MenuID":"4443798E-EB6E-4D88-BFBD-BB0A76FF6BD5","Logtype":6,"Context":"查询"}}),
headers=headers
)
data = json.loads(r.content.decode('utf-8'))
if data['state'] != 0:
return {'errcode': 102, 'errmsg': '教务挂了'}
data_cache = []
for item in data['data']['GradeList']:
data_cache.append(item['LessonInfo']['KCMC']+':'+item['ShowYXCJ'])
return {'errcode': 200, 'errmsg': 'ok', 'data': data_cache}
def getTimetable(Ip, S):
headers = {'Content-Type': 'application/json'}
r = S.post(
url='http://'+Ip[0]+'-'+Ip[1]+'-'+Ip[2]+'-'+Ip[3]+'-8080-p.webvpn.cust.edu.cn:8118/api/ClientStudent/Home/StudentHomeApi/QueryStudentScheduleData?sf_request_type=ajax',
data=json.dumps({"param":"JTdCJTdE","__permission":{"MenuID":"F71C97D5-D3E2-4FDA-9209-D7FA8626390E","Operation":0},"__log":{"MenuID":"F71C97D5-D3E2-4FDA-9209-D7FA8626390E","Logtype":6,"Context":"查询"}}),
headers=headers
)
data = json.loads(r.content.decode('utf-8'))
if data['state'] != 0:
return {'errcode': 102, 'errmsg':'教务挂了'}
time = ['AM__TimePieces','PM__TimePieces','EV__TimePieces']
data = data['data']['AdjustDays']
data_cache = [[0] * 7 for _ in range(6)]
for i in range(7):
for j in range(3):
for k in range(2):
if( data[i][time[j]][k]['Dtos'] ):
data_cache[j*2+k][i] = []
for l in range(4):
data_cache[j*2+k][i].append(data[i][time[j]][k]['Dtos'][0]['Content'][l]['Name'])
return {'errcode': 200, 'errmsg': 'ok', 'data': data_cache}