Passed
Push — master ( d2ca87...c28312 )
by dai
01:32
created

Schedule._get_api_by_bm()   C

Complexity

Conditions 9

Size

Total Lines 46
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 35
dl 0
loc 46
rs 6.6666
c 0
b 0
f 0
cc 9
nop 3
1
# -*- coding: utf-8 -*-
2
from __future__ import absolute_import, unicode_literals
3
4
from six.moves.urllib import parse
5
6
from bs4 import BeautifulSoup
7
from requests import RequestException
8
9
from school_api.client.api.base import BaseSchoolApi
10
from school_api.client.api.utils import get_alert_tip, get_view_state_from_html
11
from school_api.client.api.utils.schedule_parse import ScheduleParse
12
from school_api.client.utils import ScheduleType, UserType
13
from school_api.utils import to_text
14
from school_api.exceptions import ScheduleException
15
16
17
class Schedule(BaseSchoolApi):
18
    schedule_type = None
19
    schedule_year = None
20
    schedule_term = None
21
    schedule_url = None
22
23
    def get_schedule(self, schedule_year=None, schedule_term=None, schedule_type=None, **kwargs):
24
        ''' 课表信息 获取入口
25
        :param schedule_year: 课表学年
26
        :param schedule_term: 课表学期
27
        :param schedule_type: 0.个人课表 1.班级课表
28
        :param kwargs: requests模块参数
29
        :return:
30
        '''
31
        self.schedule_type = ScheduleType.CLASS if self.user_type \
32
            else schedule_type or ScheduleType.PERSON
33
        self.schedule_year = schedule_year
34
        self.schedule_term = str(schedule_term) if schedule_term else schedule_term
35
        self.schedule_url = self.school_url["SCHEDULE_URL"][self.schedule_type]
36
37
        if self.user_type != UserType.DEPT:
38
            self.schedule_url += self.account
39
            data = self._get_api(**kwargs)
40
        else:
41
            self.schedule_url += parse.quote(self.account.encode('gb2312'))
42
            data = self._get_api_by_bm(**kwargs)
43
        if self.schedule_term and self.schedule_year and (
44
                self.schedule_term != data["schedule_term"] or self.schedule_year != data["schedule_year"]):
45
            raise ScheduleException(self.code, '暂无课表信息')
46
        return data
47
48
    def _get_api(self, **kwargs):
49
        coding = 'gbk' if self.user_type else 'GB18030'
50
        try:
51
            res = self._get(self.schedule_url, **kwargs)
52
53
            if res.status_code == 302:
54
                raise ScheduleException(self.code, '课表接口已关闭')
55
            elif res.status_code != 200:
56
                raise RequestException
57
        except RequestException:
58
            raise ScheduleException(self.code, '获取课表请求参数失败')
59
60
        html = res.content.decode(coding)
61
        tip = get_alert_tip(html)
62
        if tip:
63
            raise ScheduleException(self.code, tip)
64
65
        schedule = ScheduleParse(html, self.time_list, self.schedule_type).get_schedule_dict()
66
        # 第一次请求的时候,教务系统默认返回当前学年学期课表
67
        # 如果设置了学年跟学期,则获取指定学年学期的课表
68
        if self.schedule_year and self.schedule_term and (
69
                self.schedule_year != schedule['schedule_year'] or self.schedule_term != schedule['schedule_term']):
70
71
            payload = self._get_payload(res.text)
72
73
            try:
74
                res = self._post(self.schedule_url, data=payload, **kwargs)
75
                if res.status_code != 200:
76
                    raise RequestException
77
            except RequestException:
78
                raise ScheduleException(self.code, '获取课表信息失败')
79
80
            html = res.content.decode(coding)
81
            schedule = ScheduleParse(
82
                html,
83
                self.time_list,
84
                self.schedule_type
85
            ).get_schedule_dict()
86
87
        return schedule
88
89
    def _get_payload(self, html):
90
        ''' 获取课表post 的参数 '''
91
        view_state = get_view_state_from_html(html)
92
        payload = {
93
            '__VIEWSTATE': view_state,
94
            ['xnd', 'xn'][self.schedule_type]: self.schedule_year,
95
            ['xqd', 'xq'][self.schedule_type]: self.schedule_term
96
        }
97
        return payload
98
99
    def _get_api_by_bm(self, class_name, **kwargs):
100
        ''' 部门教师 查询学生班级课表 共3个请求'''
101
102
        # steps 1: 获取课表 view_state
103
        try:
104
            res = self._get(self.schedule_url, **kwargs)
105
            if res.status_code != 200:
106
                raise RequestException
107
            view_state = get_view_state_from_html(res.text)
108
        except RequestException:
109
            raise ScheduleException(self.code, '获取课表请求参数失败')
110
111
        # steps 2: 选择课表 学年学期
112
        if self.schedule_year and self.schedule_term:
113
            payload = {
114
                '__VIEWSTATE': view_state,
115
                'xn': self.schedule_year,
116
                'xq': self.schedule_term
117
            }
118
            try:
119
                res = self._post(self.schedule_url, data=payload, **kwargs)
120
                if res.status_code != 200:
121
                    raise RequestException
122
            except RequestException:
123
                raise ScheduleException(self.code, '获取课表请求参数失败')
124
125
        # steps 3: 获取课表数据
126
        payload = self._get_payload_by_bm(
127
            res.content.decode('gbk'),
128
            class_name
129
        )
130
        try:
131
            res = self._post(self.schedule_url, data=payload, **kwargs)
132
            if res.status_code != 200:
133
                raise RequestException
134
        except RequestException:
135
            raise ScheduleException(self.code, '获取课表信息失败')
136
137
        html = res.content.decode('gbk')
138
        schedule = ScheduleParse(
139
            html,
140
            self.time_list,
141
            self.schedule_type
142
        ).get_schedule_dict()
143
144
        return schedule
145
146
    @staticmethod
147
    def _get_payload_by_bm(html, class_name):
148
        ''' 提取页面参数用于请求课表 '''
149
        pre_soup = BeautifulSoup(html, "html.parser")
150
        view_state = pre_soup.find(attrs={"name": "__VIEWSTATE"})['value']
151
        schedule_id_list = pre_soup.find(id='kb').find_all('option')
152
        class_name = to_text(class_name)
153
        schedule_id = ''
154
        for name in schedule_id_list:
155
            if name.text == class_name:
156
                schedule_id = name['value']
157
                break
158
159
        # 获取班级课表
160
        payload = {
161
            '__VIEWSTATE': view_state,
162
            'kb': schedule_id
163
        }
164
        return payload
165