1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 | import re
import typing as t
import bs4
import pandas as pd
import requests
Cookies = t.Dict[str, str]
Grades = t.List[t.Dict[str, t.Any]]
class TIS:
def __init__(self, cookies: Cookies) -> None:
self._cookies = cookies
self._grades = None
self._rank = None
@property
def grades(self) -> pd.DataFrame:
if self._grades is None:
self._grades = self._get_grades(self._get_fah())
keys = {
'kcdm': '课程代码', 'kcmc': '课程名称', 'kzmc': '课组名称', 'kkyxmc': '开课学院',
'xszscj': '课程成绩', 'xscj': '课程等级', 'xf': '学分',
}
df = pd.DataFrame([
tuple(grade[key] for key in keys) for grade in self._grades
])
df.columns = pd.MultiIndex.from_tuples(keys.items())
return df
@property
def gpa(self) -> float:
grade_credit = [
(int(row['xszscj'][0]), float(row['xf'][0]))
for _, row in self.grades.iterrows()
if row['xszscj'][0] is not None and row['xscj'][0] != 'P'
]
credits = sum(c for _, c in grade_credit)
if credits == 0:
return 0.0
return sum([self._mapper(g)*c for g, c in grade_credit]) / credits
@property
def sa(self) -> float:
'''Score Average'''
grade_credit = [
(int(row['xszscj'][0]), float(row['xf'][0]))
for _, row in self.grades.iterrows()
if row['xszscj'][0] is not None
]
credits = sum(c for _, c in grade_credit)
if credits == 0:
return 0.0
return sum([g*c for g, c in grade_credit]) / credits
@property
def rank(self) -> str:
'''Rank'''
if self._rank is None:
url = 'https://tis.sustech.edu.cn/cjgl/xscjgl/xsgrcjcx/queryXnAndXqXfj'
headers = {'RoleCode': '02'}
response = requests.post(url, headers=headers, cookies=self._cookies)
self._rank = response.json()['xfjandpm']['PM']
return self._rank
@classmethod
def login(cls, username: str, password: str) -> 'TIS':
url = 'https://cas.sustech.edu.cn/cas/login'
params = {'service': 'https://tis.sustech.edu.cn/cas'}
cookies = requests.get('https://tis.sustech.edu.cn').cookies
with requests.session() as session:
response = session.get(url, params=params, cookies=cookies)
soup = bs4.BeautifulSoup(response.content, 'html.parser')
execution = soup.select('input[name$="execution"]')[0]['value']
data = {
'username': username, 'password': password,
'execution': execution, '_eventId': 'submit',
}
session.post(url, params=params, data=data, cookies=cookies)
return cls(dict(cookies))
def _get_fah(self) -> str:
url = 'https://tis.sustech.edu.cn/xspyyjsfasq/grjhzd/2'
response = requests.get(url, cookies=self._cookies)
pattern = re.compile(r'(?<=var param_fah = \')[a-zA-Z0-9]+?(?=\')')
return next(pattern.finditer(response.text)).group()
def _get_grades(self, fah: str) -> Grades:
url = 'https://tis.sustech.edu.cn/xspyyjsfasq/queryFakcPage'
data = {
'fah': fah, 'loading': 'true', 'pylx': '2', 'isEdit': '1',
'multiple': 'false', 'labelyxwidth': '100', 'cksf': '1', 'sffaw': '0',
}
response = requests.post(url, cookies=self._cookies, data=data)
return response.json()['list']
def _mapper(self, grade: int) -> float:
for (boundary, value) in [
# 研究生
(95, 4.0), (90, 3.7), (85, 3.3), (80, 3.0), (77, 2.7),
(73, 2.3), (70, 2.0), (67, 1.7), (63, 1.3), (60, 1.0),
# 本科生
# (97, 4.00), (93, 3.94), (90, 3.85), (87, 3.73), (83, 3.55),
# (80, 3.32), (77, 3.09), (73, 2.78), (70, 2.42), (67, 2.08),
# (63, 1.63), (60, 1.15),
]:
if grade >= boundary:
return value
return 0.0
if __name__ == '__main__':
tis = TIS.login(input('(username) >>> '), input('(password) >>> '))
print(f'Rank: {tis.rank}')
print(f'GPA: {tis.gpa:.2f}')
print(f'SA: {tis.sa:.2f}')
print(
tis.grades
.droplevel(0, axis=1)
.sort_values(by=['课程成绩', '学分'], ascending=False)
.to_markdown(index=False)
)
|