|
1
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
2
|
|
|
from __future__ import absolute_import, unicode_literals
|
|
3
|
|
|
|
|
4
|
|
|
from bs4 import BeautifulSoup
|
|
5
|
|
|
from requests import RequestException
|
|
6
|
|
|
|
|
7
|
|
|
from school_api.client.api.base import BaseSchoolApi
|
|
8
|
|
|
from school_api.exceptions import ScoreException
|
|
9
|
|
|
|
|
10
|
|
|
|
|
11
|
|
View Code Duplication |
class Score(BaseSchoolApi):
|
|
|
|
|
|
|
12
|
|
|
''' 学生成绩获取 '''
|
|
13
|
|
|
|
|
14
|
|
|
def get_score(self, score_year=None, score_term=None, **kwargs):
|
|
15
|
|
|
''' 成绩信息 获取入口 '''
|
|
16
|
|
|
score_url = self.school_url['SCORE_URL'] + self.account
|
|
17
|
|
|
|
|
18
|
|
|
try:
|
|
19
|
|
|
view_state = self._get_view_state(score_url, **kwargs)
|
|
20
|
|
|
except RequestException:
|
|
21
|
|
|
raise ScoreException(self.code, '获取成绩请求参数失败')
|
|
22
|
|
|
|
|
23
|
|
|
payload = {
|
|
24
|
|
|
'__VIEWSTATE': view_state,
|
|
25
|
|
|
'Button2': u'在校学习成绩查询',
|
|
26
|
|
|
'ddlXN': '',
|
|
27
|
|
|
'ddlXQ': ''
|
|
28
|
|
|
}
|
|
29
|
|
|
|
|
30
|
|
|
try:
|
|
31
|
|
|
res = self._post(score_url, data=payload, **kwargs)
|
|
32
|
|
|
if res.status_code == 302:
|
|
33
|
|
|
raise ScoreException(self.code, '成绩接口已关闭')
|
|
34
|
|
|
elif res.status_code != 200:
|
|
35
|
|
|
raise RequestException
|
|
36
|
|
|
except RequestException:
|
|
37
|
|
|
raise ScoreException(self.code, '获取成绩信息失败')
|
|
38
|
|
|
|
|
39
|
|
|
return ScoreParse(res.content).get_score(score_year, score_term)
|
|
40
|
|
|
|
|
41
|
|
|
|
|
42
|
|
View Code Duplication |
class ScoreParse():
|
|
|
|
|
|
|
43
|
|
|
''' 成绩页面解析模块 '''
|
|
44
|
|
|
|
|
45
|
|
|
def __init__(self, html):
|
|
46
|
|
|
self.soup = BeautifulSoup(html.decode('GB18030'), "html.parser")
|
|
47
|
|
|
self._html_parse_of_score()
|
|
48
|
|
|
|
|
49
|
|
|
def _html_parse_of_score(self):
|
|
50
|
|
|
rows = self.soup.find("table", {"id": "Datagrid1"}).find_all('tr')
|
|
51
|
|
|
rows.pop(0)
|
|
52
|
|
|
self.score_info = {}
|
|
53
|
|
|
for row in rows:
|
|
54
|
|
|
cells = row.find_all("td")
|
|
55
|
|
|
# 学年学期
|
|
56
|
|
|
year = cells[0].text
|
|
57
|
|
|
term = cells[1].text
|
|
58
|
|
|
# 课程名
|
|
59
|
|
|
lesson_name = cells[3].text.strip()
|
|
60
|
|
|
credit = cells[6].text.strip() or 0
|
|
61
|
|
|
point = cells[7].text.strip() or 0
|
|
62
|
|
|
score = cells[8].text.strip() or 0
|
|
63
|
|
|
score_dict = {
|
|
64
|
|
|
"lesson_name": lesson_name,
|
|
65
|
|
|
"credit": float(credit),
|
|
66
|
|
|
"point": float(point),
|
|
67
|
|
|
"score": self.handle_data(score)
|
|
68
|
|
|
}
|
|
69
|
|
|
# 有其他成绩内容则输出
|
|
70
|
|
|
makeup_score = cells[10].text
|
|
71
|
|
|
retake_score = cells[11].text
|
|
72
|
|
|
if makeup_score != '\xa0':
|
|
73
|
|
|
# 补考成绩
|
|
74
|
|
|
score_dict['bkcj'] = makeup_score
|
|
75
|
|
|
if retake_score != '\xa0':
|
|
76
|
|
|
# 重修成绩
|
|
77
|
|
|
score_dict['cxcj'] = retake_score
|
|
78
|
|
|
# 组装数组格式的数据备用
|
|
79
|
|
|
self.score_info[year] = self.score_info.get(year, {})
|
|
80
|
|
|
self.score_info[year][term] = self.score_info[year].get(term, [])
|
|
81
|
|
|
self.score_info[year][term].append(score_dict)
|
|
82
|
|
|
|
|
83
|
|
|
def get_score(self, year, term):
|
|
84
|
|
|
''' 返回成绩信息json格式 '''
|
|
85
|
|
|
if year:
|
|
86
|
|
|
if term:
|
|
87
|
|
|
return self.score_info[year][term]
|
|
88
|
|
|
return self.score_info[year]
|
|
89
|
|
|
return self.score_info
|
|
90
|
|
|
|
|
91
|
|
|
@staticmethod
|
|
92
|
|
|
def handle_data(data):
|
|
|
|
|
|
|
93
|
|
|
try:
|
|
94
|
|
|
return float(data)
|
|
95
|
|
|
except ValueError:
|
|
96
|
|
|
return data
|
|
97
|
|
|
|
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.