|
1
|
|
|
# -*- coding: utf-8 -*- |
|
2
|
|
|
from __future__ import absolute_import, unicode_literals |
|
3
|
|
|
|
|
4
|
|
|
from requests import RequestException, TooManyRedirects |
|
5
|
|
|
from six.moves.urllib import parse |
|
6
|
|
|
|
|
7
|
|
|
from school_api.check_code import CHECK_CODE |
|
8
|
|
|
from school_api.client.api.base import BaseSchoolApi |
|
9
|
|
|
from school_api.client.api.utils import get_alert_tip, get_view_state_from_html |
|
10
|
|
|
from school_api.exceptions import IdentityException, CheckCodeException, LoginException, \ |
|
11
|
|
|
OtherException |
|
12
|
|
|
from school_api.utils import to_binary, to_text |
|
13
|
|
|
|
|
14
|
|
|
|
|
15
|
|
|
class Login(BaseSchoolApi): |
|
16
|
|
|
''' 登录模块 ''' |
|
17
|
|
|
|
|
18
|
|
|
def get_login(self, school, **kwargs): |
|
19
|
|
|
''' 登录入口 与 异常处理 ''' |
|
20
|
|
|
args = (school.login_url, school.exist_verify) |
|
21
|
|
|
try: |
|
22
|
|
|
res = self._get_api(*args, **kwargs) |
|
23
|
|
|
except OtherException as reqe: |
|
24
|
|
|
raise LoginException(self.school_code, to_text(str(reqe))) |
|
25
|
|
|
|
|
26
|
|
|
except RequestException: |
|
27
|
|
|
if school.proxies and not self.user.proxy_state: |
|
28
|
|
|
# 使用内网代理 |
|
29
|
|
|
proxy_session = self._switch_proxy() |
|
30
|
|
|
if proxy_session: |
|
31
|
|
|
# 存在内网代理会话 |
|
32
|
|
|
return True |
|
33
|
|
|
try: |
|
34
|
|
|
res = self._get_api(*args, **kwargs) |
|
35
|
|
|
except RequestException: |
|
36
|
|
|
raise LoginException(self.school_code, '教务系统异常,切用代理登录失败') |
|
37
|
|
|
else: |
|
38
|
|
|
|
|
39
|
|
|
if self.user.proxy_state: |
|
40
|
|
|
raise LoginException(self.school_code, '教务系统异常,使用代理登录失败') |
|
41
|
|
|
else: |
|
42
|
|
|
raise LoginException(self.school_code, '教务系统外网异常') |
|
43
|
|
|
|
|
44
|
|
|
# 处理登录结果 |
|
45
|
|
|
try: |
|
46
|
|
|
self._handle_login_result(res) |
|
47
|
|
|
except CheckCodeException: |
|
48
|
|
|
try: |
|
49
|
|
|
# 验证码错误时,再次登录 |
|
50
|
|
|
res = self._get_api(*args, **kwargs) |
|
51
|
|
|
except RequestException: |
|
52
|
|
|
raise LoginException(self.school_code, '教务系统请求异常') |
|
53
|
|
|
else: |
|
54
|
|
|
self._handle_login_result(res) |
|
55
|
|
|
|
|
56
|
|
|
return True |
|
57
|
|
|
|
|
58
|
|
|
def _handle_login_result(self, res): |
|
59
|
|
|
''' 处理页面弹框信息 ''' |
|
60
|
|
|
if res is True: |
|
61
|
|
|
# 登录成功 |
|
62
|
|
|
return |
|
63
|
|
|
tip = get_alert_tip(res.text) |
|
64
|
|
|
if tip: |
|
65
|
|
|
if tip == '验证码不正确!!': |
|
66
|
|
|
raise CheckCodeException(self.school_code, tip) |
|
67
|
|
|
raise IdentityException(self.school_code, tip) |
|
68
|
|
|
raise LoginException(self.school_code, '教务系统请求异常') |
|
69
|
|
|
|
|
70
|
|
|
def _get_login_payload(self, login_url, **kwargs): |
|
71
|
|
|
''' 获取登录页面的 请求参数''' |
|
72
|
|
|
try: |
|
73
|
|
|
kwargs['timeout'] = 3 |
|
74
|
|
|
res = self._get(login_url, **kwargs) |
|
75
|
|
|
except TooManyRedirects as reqe: |
|
76
|
|
|
res = self._get(reqe.response.headers["Location"], **kwargs) |
|
77
|
|
|
|
|
78
|
|
|
except RequestException: |
|
79
|
|
|
# 首次请求可能出现 Connection aborted |
|
80
|
|
|
res = self._get(login_url, **kwargs) |
|
81
|
|
|
|
|
82
|
|
|
url_info = res.url.split(login_url)[0].split('/(') |
|
83
|
|
|
if len(url_info) == 2: |
|
84
|
|
|
self._update_url_token('/(' + url_info[1]) |
|
85
|
|
|
|
|
86
|
|
|
view_state = get_view_state_from_html(res.text) |
|
87
|
|
|
return {'__VIEWSTATE': view_state} |
|
88
|
|
|
|
|
89
|
|
|
def _get_api(self, login_url, exist_verify, **kwargs): |
|
90
|
|
|
# 登录请求 |
|
91
|
|
|
code = '' |
|
92
|
|
|
login_types = ['学生', '教师', '部门'] |
|
93
|
|
|
login_payload = self._get_login_payload(login_url, **kwargs) |
|
94
|
|
|
if exist_verify: |
|
95
|
|
|
res = self._get('/CheckCode.aspx') |
|
96
|
|
|
if res.content[:7] != to_binary('GIF89aH'): |
|
97
|
|
|
raise CheckCodeException(self.school_code, "验证码获取失败") |
|
98
|
|
|
code = CHECK_CODE.verify(res.content) |
|
99
|
|
|
|
|
100
|
|
|
account = self.user.account.encode('gb2312') |
|
101
|
|
|
payload = { |
|
102
|
|
|
'txtUserName': account, |
|
103
|
|
|
'TextBox1': account, |
|
104
|
|
|
'TextBox2': self.user.password, |
|
105
|
|
|
'TextBox3': code, |
|
106
|
|
|
'txtSecretCode': code, |
|
107
|
|
|
'RadioButtonList1': login_types[self.user.user_type].encode('gb2312'), |
|
108
|
|
|
'Button1': ' 登 录 '.encode('gb2312') |
|
109
|
|
|
} |
|
110
|
|
|
payload.update(login_payload) |
|
111
|
|
|
try: |
|
112
|
|
|
res = self._post(login_url, data=payload, **kwargs) |
|
113
|
|
|
except TooManyRedirects: |
|
114
|
|
|
# 302跳转 代表登录成功 |
|
115
|
|
|
return True |
|
116
|
|
|
return res |
|
117
|
|
|
|
|
118
|
|
|
def check_session(self): |
|
119
|
|
|
""" 检查登陆会话是否有效 """ |
|
120
|
|
|
account = parse.quote(self.user.account.encode('gb2312')) |
|
121
|
|
|
try: |
|
122
|
|
|
self._head(self.school_url['HOME_URL'] + account) |
|
123
|
|
|
except RequestException: |
|
124
|
|
|
return False |
|
125
|
|
|
|
|
126
|
|
|
return True |
|
127
|
|
|
|