school_api.client.api.score.Score.get_score()   B
last analyzed

Complexity

Conditions 6

Size

Total Lines 39
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 27
nop 5
dl 0
loc 39
rs 8.2986
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2
from __future__ import absolute_import, unicode_literals
3
4
import re
5
from bs4 import BeautifulSoup
6
from requests import RequestException, TooManyRedirects
7
8
from school_api.client.api.base import BaseSchoolApi
9
from school_api.client.api.utils import get_alert_tip
10
from school_api.exceptions import ScoreException
11
12
13
class Score(BaseSchoolApi):
14
    ''' 学生成绩获取 '''
15
16
    def get_score(self, score_year=None, score_term=None, use_api=0, **kwargs):
17
        ''' 成绩信息 获取入口
18
        :param score_year: 成绩学年
19
        :param score_term: 成绩学期
20
        :param use_api:    0.接口1, 1.接口2, 2.接口3 ...
21
        :param kwargs: requests模块参数
22
        return
23
        '''
24
        score_url = self.school_url['SCORE_URL'][use_api] + self.user.account
25
26
        try:
27
            view_state = self._get_view_state(score_url, **kwargs)
28
        except TooManyRedirects:
29
            msg = '可能是成绩接口地址不对,请尝试更改use_api值'
30
            raise ScoreException(self.school_code, msg)
31
        except RequestException:
32
            msg = '获取成绩请求参数失败'
33
            raise ScoreException(self.school_code, msg)
34
35
        payload = {
36
            '__VIEWSTATE': view_state,
37
            'Button2': '在校学习成绩查询',
38
            'btn_zcj': '历年成绩',
39
            'btnCx': ' 查  询 ',
40
            'ddlXN': '',
41
            'ddlXQ': ''
42
        }
43
        try:
44
            res = self._post(score_url, data=payload, **kwargs)
45
        except TooManyRedirects:
46
            raise ScoreException(self.school_code, '成绩接口已关闭')
47
        except RequestException:
48
            raise ScoreException(self.school_code, '获取成绩信息失败')
49
50
        tip = get_alert_tip(res.text)
51
        if tip:
52
            raise ScoreException(self.school_code, tip)
53
54
        return ScoreParse(self.school_code, res.text, use_api).get_score(score_year, score_term)
55
56
57
class ScoreParse():
58
    ''' 成绩页面解析模块 '''
59
60
    def __init__(self, school_code, html, use_api):
61
        self.school_code = school_code
62
        self.use_api = use_api
63
        self.soup = BeautifulSoup(html, "html.parser")
64
        self._html_parse_of_score()
65
66
    def _html_parse_of_score(self):
67
        table = self.soup.find("table", {"id": re.compile("Datagrid1", re.IGNORECASE)})
68
        if not table:
69
            raise ScoreException(self.school_code, '获取成绩信息失败')
70
71
        rows = table.find_all('tr')
72
        rows.pop(0)
73
        self.score_info = {}
74
        for row in rows:
75
            cells = row.find_all("td")
76
            # 学年学期
77
            year = cells[0].text
78
            term = cells[1].text
79
            # 课程名
80
            lesson_name = cells[3].text.strip()
81
            credit = cells[6].text.strip() or 0
82
            point = cells[7].text.strip() or 0
83
            score = cells[8].text.strip() or 0
84
            score_dict = {
85
                "lesson_name": lesson_name,
86
                "credit": float(credit),
87
                "point": float(point),
88
                "score": self.handle_data(score)
89
            }
90
            # 有其他成绩内容则输出
91
            makeup_score = cells[10].text
92
            retake_score = cells[11].text
93
            if makeup_score != '\xa0':
94
                # 补考成绩
95
                score_dict['bkcj'] = makeup_score
96
            if retake_score != '\xa0':
97
                # 重修成绩
98
                score_dict['cxcj'] = retake_score
99
            # 组装数组格式的数据备用
100
            self.score_info[year] = self.score_info.get(year, {})
101
            self.score_info[year][term] = self.score_info[year].get(term, [])
102
            self.score_info[year][term].append(score_dict)
103
104
    def get_score(self, year, term):
105
        ''' 返回成绩信息json格式 '''
106
        try:
107
            if not self.score_info:
108
                raise KeyError
109
            if year:
110
                if term:
111
                    return self.score_info[year][term]
112
                return self.score_info[year]
113
        except KeyError:
114
            raise ScoreException(self.school_code, '暂无成绩信息')
115
116
        return self.score_info
117
118
    @staticmethod
119
    def handle_data(data):
120
        try:
121
            return float(data)
122
        except ValueError:
123
            return data
124