Completed
Push — master ( 807b56...2298c4 )
by dai
04:52
created

school_api.client.base   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 147
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 104
dl 0
loc 147
rs 10
c 0
b 0
f 0
wmc 16

1 Function

Rating   Name   Duplication   Size   Complexity  
A _is_api_endpoint() 0 2 1

8 Methods

Rating   Name   Duplication   Size   Complexity  
A BaseUserClient.get() 0 5 1
A BaseUserClient.switch_proxy() 0 13 2
A BaseUserClient.post() 0 5 1
A BaseUserClient.get_view_state() 0 8 2
A BaseUserClient.__init__() 0 19 2
A BaseUserClient.__new__() 0 8 2
A BaseUserClient.update_url_token() 0 3 1
A BaseUserClient._request() 0 16 1
1
# -*- coding: utf-8 -*-
2
from __future__ import absolute_import, unicode_literals
3
4
import inspect
5
import requests
6
7
from school_api.client.utils import get_time_list
8
from school_api.client.api.base import BaseSchoolApi
9
10
from school_api.client.api.utils import get_view_state_from_html
11
from school_api.client.login_management import LoginManagement
12
from school_api.session.memorystorage import MemoryStorage
13
from school_api.utils import to_text, ObjectDict
14
from school_api.config import URL_ENDPOINT, CLASS_TIME
15
16
17
def _is_api_endpoint(obj):
18
    return isinstance(obj, BaseSchoolApi)
19
20
21
class BaseSchoolClient(object):
22
23
    def __init__(self, url, **kwargs):
24
        url = url.split('/default')[0] if url[-4:] == 'aspx' else url
25
        class_time_list = kwargs.get('class_time_list') or CLASS_TIME
26
        time_list = get_time_list(class_time_list)
27
28
        self.school = {
29
            'url': url,
30
            'debug': kwargs.get('debug'),
31
            'name': to_text(kwargs.get('name')),
32
            'code': kwargs.get('code'),
33
            'use_ex_handle': kwargs.get('use_ex_handle', True),
34
            'exist_verify': kwargs.get('exist_verify', True),
35
            'lan_url': kwargs.get('lan_url'),
36
            'proxies': kwargs.get('proxies'),
37
            'priority_proxy': kwargs.get('priority_proxy'),
38
            'timeout': kwargs.get('timeout', 10),
39
            'login_url': kwargs.get('login_url_path', '/default2.aspx'),
40
            'url_endpoint': kwargs.get('url_endpoint') or URL_ENDPOINT,
41
            'time_list': time_list
42
        }
43
        storage = kwargs.get('session', MemoryStorage)
44
        self.session = storage(self.school['code'])
45
        self.school = ObjectDict(self.school)
46
47
48
class BaseUserClient(LoginManagement):
49
    """docstring for BaseUserClient"""
50
51
    _proxy = None
52
    url_token = ''
53
54
    def __new__(cls, *args):
55
        self = super(BaseUserClient, cls).__new__(cls)
56
        api_endpoints = inspect.getmembers(self, _is_api_endpoint)
57
        for name, api in api_endpoints:
58
            api_cls = type(api)
59
            api = api_cls(self)
60
            setattr(self, name, api)
61
        return self
62
63
    def __init__(self, school, account, password, user_type):
64
        self._http = requests.Session()
65
66
        self.account = to_text(account)
67
        self.password = password
68
        self.user_type = user_type
69
        self.school = school.school
70
        self.base_url = self.school.url
71
        self.session = school.session
72
73
        self._http.headers.update({
74
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) '
75
                          'AppleWebKit/537.36 (KHTML, like Gecko) '
76
                          'Chrome/62.0.3202.89 Safari/537.36',
77
            'Content-Type': 'application/x-www-form-urlencoded',
78
            'Referer': self.base_url + self.school.login_url
79
        })
80
        if self.school.priority_proxy:
81
            self.switch_proxy()
82
83
    def _request(self, method, url_or_endpoint, **kwargs):
84
85
        url = '{base}{url_token}{endpoint}'.format(
86
            base=self.base_url,
87
            endpoint=url_or_endpoint,
88
            url_token=self.url_token
89
        )
90
91
        kwargs['timeout'] = kwargs.get('timeout', self.school.timeout)
92
        res = self._http.request(
93
            method=method,
94
            url=url,
95
            proxies=self._proxy,
96
            **kwargs
97
        )
98
        return res
99
100
    def get(self, url, **kwargs):
101
        return self._request(
102
            method='GET',
103
            url_or_endpoint=url,
104
            **kwargs
105
        )
106
107
    def post(self, url, **kwargs):
108
        return self._request(
109
            method='POST',
110
            url_or_endpoint=url,
111
            **kwargs
112
        )
113
114
    def head(self, url, **kwargs):
115
        return self._request(
116
            method='HEAD',
117
            url_or_endpoint=url,
118
            **kwargs
119
        )
120
121
    def switch_proxy(self):
122
        """ 设置代理 """
123
        self.base_url = self.school.lan_url or self.base_url
124
        self._proxy = self.school.proxies
125
        self._http.headers.update({
126
            'Referer': self.base_url + self.school.login_url
127
        })
128
129
        if not self.school.priority_proxy:
130
            # 检查是否有登录会话
131
            return self.get_login_session()
132
133
        self.school.priority_proxy = True
134
135
    def get_view_state(self, url_suffix, **kwargs):
136
        """ 获取页面 view_state 值"""
137
        res = self.get(url_suffix, allow_redirects=False, **kwargs)
138
        res.raise_for_status()
139
        if res.status_code == 302:
140
            raise requests.TooManyRedirects
141
142
        return get_view_state_from_html(res.text)
143
144
    def update_url_token(self, url_token):
145
        # 兼容含token的教务系统请求地址 http://xxx.xxx/(35yxiq45pv0ojz45wcopgz45)/Default2.aspx
146
        self.url_token = url_token