Passed
Push — master ( 5fd33b...e0a73e )
by dai
01:40
created

PlaceSchedule._is_skip()   A

Complexity

Conditions 5

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 3
nop 4
dl 0
loc 3
rs 9.3333
c 0
b 0
f 0
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,
0 ignored issues
show
best-practice introduced by
Too many arguments (8/5)
Loading history...
Comprehensibility introduced by
This function exceeds the maximum number of variables (17/15).
Loading history...
20
                     campus_list=None,
21
                     building_list=None,
22
                     classroom_type_list=None,
23
                     classroom_name_list=None,
24
                     filter_campus_list=None,
25
                     filter_building_list=None,
26
                     filter_classroom_type_list=None,
27
                     **kwargs):
28
        ''' 课表信息 获取入口
29
        返回一个生成器,生成器一旦报错则将退出:https://codeday.me/bug/20180125/124136.html
30
        除了解析异常其他报错均不抛出
31
        '''
32
        self.schedule_url = self.school_url['PLACE_SCHEDULE_URL'] + \
33
            urlparse.quote(self.account.encode('gb2312'))
34
35
        if not self._update_payload(**kwargs):
0 ignored issues
show
unused-code introduced by
Too many nested blocks (6/5)
Loading history...
36
            yield {'error': "获取教学场地课表失败"}
37
        else:
38
            # 遍历校区
39
            for campus in self.payload['campus_list']:
40
                if self._is_skip(campus["name"], campus_list, filter_name_list=filter_campus_list):
41
                    continue
42
                if not self._update_payload(campus, **kwargs):
43
                    continue
44
45
                # 遍历楼号
46
                for building in self.payload['building_list']:
47
                    kwargs['building'] = building
48
                    if self._is_skip(building["name"], building_list, filter_name_list=filter_building_list):
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (109/100).

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

Loading history...
49
                        continue
50
                    if not self._update_payload(campus, **kwargs):
51
                        continue
52
53
                    # 遍历教室类别
54
                    for classroom_type in self.payload['classroom_type_list']:
55
                        kwargs['classroom_type'] = classroom_type
56
                        if self._is_skip(classroom_type["name"], classroom_type_list, filter_name_list=filter_classroom_type_list):
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (131/100).

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

Loading history...
57
                            continue
58
                        if not self._update_payload(campus, **kwargs):
59
                            continue
60
                        # 遍历教室名称
61
                        for classroom_name in self.payload['classroom_name_list']:
62
                            kwargs['classroom_name'] = classroom_name
63
                            if self._is_skip(classroom_name["name"], classroom_name_list):
64
                                continue
65
                            try:
66
                                res = self._get_api(campus, **kwargs)
67
                            except ScheduleException:
68
                                continue
69
70
                            schedule = ScheduleParse(
71
                                res.content.decode('GB18030'),
72
                                self.time_list,
73
                                ScheduleType.CLASS
74
                            ).get_schedule_dict()
75
76
                            data = {
77
                                "campus": campus["name"],
78
                                "building": building["name"],
79
                                "classroom_type": classroom_type["name"],
80
                                "classroom_name": classroom_name["name"]
81
                            }
82
                            data.update(schedule)
83
                            yield data
84
85
    def _is_skip(self, name, name_list, filter_name_list=None):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
86
        if (name_list and name not in name_list) or (filter_name_list and name in filter_name_list):
87
            return True
88
89
    def _get_api(self, campus=None, **kwargs):
90
        """ 请求函数 """
91
        if self.payload and campus:
92
            building = kwargs.pop('building', None)
93
            classroom_type = kwargs.pop('classroom_type', None)
94
            classroom_name = kwargs.pop('classroom_name', None)
95
            data = {
96
                "Button1": "",
97
                "xq": self.payload['schedule_term'],
98
                "xn": self.payload['schedule_year'],
99
                "ddlXq": campus["value"],
100
                'ddllh': building["value"] if building else '',
101
                "ddlJslb": classroom_type["value"].encode('gb2312') if classroom_type else '',
102
                "ddlJsmc": classroom_name["value"].encode('gb2312') if classroom_name else '',
103
                "__VIEWSTATE": self.payload['view_state'],
104
            }
105
            _request = self._post
106
        else:
107
            data = ""
108
            _request = self._get
109
110
        try:
111
            res = _request(self.schedule_url, data=data, **kwargs)
112
            if res.status_code != 200:
113
                raise RequestException
114
        except RequestException:
115
            raise ScheduleException(self.code, '获取教学场地课表失败')
116
        return res
117
118
    def _update_payload(self, *args, **kwargs):
119
        # 更新提交参数 payload
120
        try:
121
            res = self._get_api(*args, **kwargs)
122
        except ScheduleException:
123
            return None
124
        self.payload = self._get_payload(res.text)
125
        return True
126
127
    @staticmethod
128
    def _get_payload(html):
0 ignored issues
show
Comprehensibility introduced by
This function exceeds the maximum number of variables (16/15).
Loading history...
129
        pre_soup = BeautifulSoup(html, "html.parser")
130
        view_state = pre_soup.find(attrs={"name": "__VIEWSTATE"})['value']
131
        searchbox = pre_soup.find("div", {"class": "searchbox"})
132
133
        schedule_year = searchbox.find("select", {"id": "xn"}).find(
134
            "option", {"selected": "selected"}).text
135
        schedule_term = searchbox.find("select", {"id": "xq"}).find(
136
            "option", {"selected": "selected"}).text
137
138
        campus = searchbox.find(id='ddlXq').find_all('option')
139
        buildings = searchbox.find(id='ddllh').find_all('option')
140
        types = searchbox.find(id='ddlJslb').find_all('option')
141
        names = searchbox.find(id='ddlJsmc').find_all('option')
142
143
        campus_list = [{"name": v.text, "value": v['value']} for v in campus]
144
        building_list = [{"name": v.text, "value": v['value']} for v in buildings]
145
        type_list = [{"name": v.text, "value": v['value']} for v in types]
146
        name_list = [{"name": v.text, "value": v['value']} for v in names]
147
148
        payload = {
149
            'view_state': view_state,
150
            'schedule_term': schedule_term,
151
            'schedule_year': schedule_year,
152
            'campus_list': campus_list,
153
            'building_list': building_list,
154
            'classroom_type_list': type_list,
155
            'classroom_name_list': name_list,
156
        }
157
        return payload
158