school_api.client.api.schedule   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 94
dl 0
loc 138
rs 10
c 0
b 0
f 0
wmc 28

5 Methods

Rating   Name   Duplication   Size   Complexity  
B Schedule.get_schedule() 0 24 8
A Schedule._get_payload() 0 9 1
A Schedule._get_payload_by_bm() 0 19 4
C Schedule._get_api() 0 33 9
B Schedule._get_api_by_bm() 0 26 6
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, TooManyRedirects
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.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.user_type != UserType.DEPT:
38
            self.schedule_url += self.user.account
39
            data = self._get_api(**kwargs)
40
        else:
41
            self.schedule_url += parse.quote(self.user.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.school_code, '暂无课表信息')
46
        return data
47
48
    def _get_api(self, **kwargs):
49
50
        try:
51
            res = self._get(self.schedule_url, **kwargs)
52
        except TooManyRedirects:
53
            raise ScheduleException(self.school_code, '课表接口已关闭')
54
        except RequestException:
55
            raise ScheduleException(self.school_code, '获取课表请求参数失败')
56
57
        tip = get_alert_tip(res.text)
58
        if tip:
59
            raise ScheduleException(self.school_code, tip)
60
61
        schedule = ScheduleParse(res.text, self.time_list, self.schedule_type).get_schedule_dict()
62
        # 第一次请求的时候,教务系统默认返回当前学年学期课表
63
        # 如果设置了学年跟学期,则获取指定学年学期的课表
64
        if self.schedule_year and self.schedule_term and (
65
                self.schedule_year != schedule['schedule_year'] or self.schedule_term != schedule['schedule_term']):
66
67
            payload = self._get_payload(res.text)
68
69
            try:
70
                res = self._post(self.schedule_url, data=payload, **kwargs)
71
            except RequestException:
72
                raise ScheduleException(self.school_code, '获取课表信息失败')
73
74
            schedule = ScheduleParse(
75
                res.text,
76
                self.time_list,
77
                self.schedule_type
78
            ).get_schedule_dict()
79
80
        return schedule
81
82
    def _get_api_by_bm(self, class_name, **kwargs):
83
        ''' 部门教师 查询学生班级课表 共3个请求'''
84
85
        # steps 1: 获取课表页面 参数信息
86
        try:
87
            res = self._get(self.schedule_url, **kwargs)
88
        except RequestException:
89
            raise ScheduleException(self.school_code, '获取课表请求参数失败')
90
91
        # steps 2: 选择课表 学年学期
92
        if self.schedule_year and self.schedule_term:
93
            payload = self._get_payload(res.text)
94
            try:
95
                res = self._post(self.schedule_url, data=payload, **kwargs)
96
            except RequestException:
97
                raise ScheduleException(self.school_code, '获取课表请求参数失败')
98
99
        # steps 3: 获取课表数据
100
        payload = self._get_payload_by_bm(res.text, class_name)
101
        try:
102
            res = self._post(self.schedule_url, data=payload, **kwargs)
103
        except RequestException:
104
            raise ScheduleException(self.school_code, '获取课表信息失败')
105
106
        schedule = ScheduleParse(res.text, self.time_list, self.schedule_type).get_schedule_dict()
107
        return schedule
108
109
    def _get_payload(self, html):
110
        ''' 获取课表post 的参数 '''
111
        view_state = get_view_state_from_html(html)
112
        payload = {
113
            '__VIEWSTATE': view_state,
114
            ['xnd', 'xn'][self.schedule_type]: self.schedule_year,
115
            ['xqd', 'xq'][self.schedule_type]: self.schedule_term
116
        }
117
        return payload
118
119
    def _get_payload_by_bm(self, html, class_name):
120
        ''' 提取页面参数用于请求课表 '''
121
        pre_soup = BeautifulSoup(html, "html.parser")
122
        view_state = pre_soup.find(attrs={"name": "__VIEWSTATE"})['value']
123
        schedule_id_list = pre_soup.find(id='kb').find_all('option')
124
        class_name = to_text(class_name)
125
        for name in schedule_id_list:
126
            if name.text == class_name:
127
                schedule_id = name['value']
128
                break
129
        else:
130
            raise ScheduleException(self.school_code, '暂无该班级课表信息')
131
132
        # 获取班级课表
133
        payload = {
134
            '__VIEWSTATE': view_state,
135
            'kb': schedule_id
136
        }
137
        return payload
138