Passed
Push — master ( dfd07f...09487a )
by dai
01:39
created

school_api.client.api.place_schedule   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 128
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 99
dl 0
loc 128
rs 10
c 0
b 0
f 0
wmc 24

4 Methods

Rating   Name   Duplication   Size   Complexity  
F PlaceSchedule.get_schedule() 0 47 14
A PlaceSchedule._get_payload() 0 26 1
A PlaceSchedule._update_payload() 0 7 2
B PlaceSchedule._get_api() 0 26 7
1
# -*- coding: utf-8 -*-
0 ignored issues
show
Coding Style introduced by
This module should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
2
from __future__ import absolute_import, unicode_literals
3
4
import six.moves.urllib.parse as urlparse
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.schedule_parse import ScheduleParse
11
from school_api.client.utils import ScheduleType
12
from school_api.exceptions import ScheduleException
13
14
15
class PlaceSchedule(BaseSchoolApi):
0 ignored issues
show
Coding Style introduced by
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
16
    schedule_url = None
17
    payload = None
18
19
    def get_schedule(self, campus_list=None, classroom_type_list=None, classroom_name_list=None, **kwargs):
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (107/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
20
        ''' 课表信息 获取入口
21
        返回一个生成器,生成器一旦报错则将退出:https://codeday.me/bug/20180125/124136.html
22
        除了解析异常其他报错均不抛出
23
        '''
24
        self.schedule_url = self.school_url['PLACE_SCHEDULE_URL'] + \
25
            urlparse.quote(self.account.encode('gb2312'))
26
27
        if not self._update_payload(**kwargs):
28
            yield {'error': "获取教学场地课表失败"}
29
        else:
30
            # 遍历校区
31
            for campus in self.payload['campus_list']:
32
                if campus_list and campus["name"] not in campus_list:
33
                    continue
34
                if not self._update_payload(campus, **kwargs):
35
                    continue
36
                # 遍历教室类别
37
                for classroom_type in self.payload['classroom_type_list']:
38
                    if classroom_type_list and classroom_type["name"] not in classroom_type_list:
39
                        continue
40
                    if not self._update_payload(campus, classroom_type=classroom_type, **kwargs):
41
                        continue
42
                    # 遍历教室名称
43
                    for classroom_name in self.payload['classroom_name_list']:
44
                        if classroom_name_list and classroom_name["name"] not in classroom_name_list:
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (101/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
45
                            continue
46
                        try:
47
                            res = self._get_api(
48
                                campus, classroom_type=classroom_type,
49
                                classroom_name=classroom_name, **kwargs)
50
                        except ScheduleException:
51
                            continue
52
53
                        schedule = ScheduleParse(
54
                            res.content.decode('GB18030'),
55
                            self.time_list,
56
                            ScheduleType.CLASS
57
                        ).get_schedule_dict()
58
59
                        data = {
60
                            "campus": campus["name"],
61
                            "classroom_type": classroom_type["name"],
62
                            "classroom_name": classroom_name["name"]
63
                        }
64
                        data.update(schedule)
65
                        yield data
66
67
    def _get_api(self, campus=None, **kwargs):
68
        """ 请求函数 """
69
        if self.payload and campus:
70
            classroom_type = kwargs.pop('classroom_type', None)
71
            classroom_name = kwargs.pop('classroom_name', None)
72
            data = {
73
                "Button1": "",
74
                "xq": self.payload['schedule_term'],
75
                "xn": self.payload['schedule_year'],
76
                "ddlXq": campus["value"],
77
                "ddlJslb": classroom_type["value"].encode('gb2312') if classroom_type else '',
78
                "ddlJsmc": classroom_name["value"].encode('gb2312') if classroom_name else '',
79
                "__VIEWSTATE": self.payload['view_state'],
80
            }
81
            _request = self._post
82
        else:
83
            data = ""
84
            _request = self._get
85
86
        try:
87
            res = _request(self.schedule_url, data=data, **kwargs)
88
            if res.status_code != 200:
89
                raise RequestException
90
        except RequestException:
91
            raise ScheduleException(self.code, '获取教学场地课表失败')
92
        return res
93
94
    def _update_payload(self, *args, **kwargs):
95
        try:
96
            res = self._get_api(*args, **kwargs)
97
        except ScheduleException:
98
            return None
99
        self.payload = self._get_payload(res.text)
100
        return True
101
102
    @staticmethod
103
    def _get_payload(html):
104
        pre_soup = BeautifulSoup(html, "html.parser")
105
        view_state = pre_soup.find(attrs={"name": "__VIEWSTATE"})['value']
106
        searchbox = pre_soup.find("div", {"class": "searchbox"})
107
108
        schedule_year = searchbox.find("select", {"id": "xn"}).find(
109
            "option", {"selected": "selected"}).text
110
        schedule_term = searchbox.find("select", {"id": "xq"}).find(
111
            "option", {"selected": "selected"}).text
112
113
        campus = searchbox.find(id='ddlXq').find_all('option')
114
        type_list = searchbox.find(id='ddlJslb').find_all('option')
115
        name_list = searchbox.find(id='ddlJsmc').find_all('option')
116
        campus_list = [{"name": v.text, "value": v['value']} for v in campus]
117
        type_list = [{"name": v.text, "value": v['value']} for v in type_list]
118
        name_list = [{"name": v.text, "value": v['value']} for v in name_list]
119
        payload = {
120
            'view_state': view_state,
121
            'schedule_term': schedule_term,
122
            'schedule_year': schedule_year,
123
            'campus_list': campus_list,
124
            'classroom_type_list': type_list,
125
            'classroom_name_list': name_list,
126
        }
127
        return payload
128