forked from iloghyr/21tb_robot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
study_robot.py
358 lines (323 loc) · 11.9 KB
/
study_robot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
#!/usr/bin/env python
#encoding: utf8
"""
Created on 2016-7-29
Author: loghyr
Mail: [email protected]
Tips: 21tb在线学习网站课程学习脚本,自动学习机器人
"""
import os
import sys
import copy
import json
import time
import datetime
import requests
import ConfigParser
reload(sys)
sys.setdefaultencoding('utf-8')
"""conf文件名的定义"""
kConfFileName = "main0.conf"
def log(info):
"""simple log"""
print time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), info
sys.stdout.flush()
class Http(object):
"""http client"""
def __init__(self):
"""init"""
self.session = requests.Session()
self.eln_session_id = None
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36'
' (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest',
}
@classmethod
def instance(cls):
"""
get instance of this module
"""
key = "__instance__"
if hasattr(cls, key):
return getattr(cls, key)
else:
http = Http()
setattr(cls, key, http)
return http
def get_session_id(self):
"""get cookie elsSign, patch it to get/port request param"""
return self.session.cookies.get('eln_session_id')
def post(self, api, params=None, json_ret=True):
"""
send post request
Params:
api: request url
params: dict or just set None
"""
if not params:
params = {'elsSign': self.get_session_id()}
else:
params.update({'elsSign': self.get_session_id()})
r = self.session.post(api, params, headers=self.headers)
if json_ret:
return r.json()
return r.text
def get(self, api, json_ret=True):
"""
send get request
Params:
api: request url
"""
r = self.session.get(api, params={'elsSign': self.get_session_id()}, headers=self.headers)
if json_ret:
return r.json()
return r.text
class ConfigMgr(object):
"""
All configuration operation is CRUD by this class
"""
def __init__(self):
"""
init
"""
self._configer = None
self.work_dir = os.path.dirname(__file__)
self.config_file = os.path.join(self.work_dir, kConfFileName)
def init(self):
"""
load config file
"""
config_file = self.config_file
if not os.path.exists(self.config_file):
raise Exception("config file %s is missing!" % config_file)
self._configer = ConfigParser.ConfigParser()
readok = self._configer.read(config_file)
if config_file not in readok:
raise Exception("load config file %s failed" % config_file)
log("load config %s" % config_file)
def get_section_items(self, section):
"""
get sepcific section configs in config file as dict
"""
if self._configer is not None:
configs = self._configer.items(section)
return dict(configs)
raise Exception("config file not loaded")
class Study(object):
"""
21tb auto study class
"""
def __init__(self):
"""init"""
#http client instance
self.http = Http.instance()
self.config = ConfigMgr()
self.config.init()
self.apis = self.init_api()
def init_api(self):
"""init api from config"""
return {
#登录接口
'login': self._make_api('login'),
'save_progress': self._make_api('save_progress'),
'course_item': self._make_api('course_item'),
'select_resourse': self._make_api('select_resourse'),
'select_check': self._make_api('select_check'),
'update_timestep': self._make_api('update_timestep'),
'course_show': self._make_api('course_show'),
'heartbeat': self._make_api('heartbeat'),
'course_center': self._make_api('course_center'),
'enter_course': self._make_api('enter_course')
}
def _make_api(self, api):
"""gen api full url"""
apis_conf = self.config.get_section_items('api')
if api in apis_conf:
return '%s%s' % (apis_conf['host'], apis_conf[api])
raise Exception('api:%s is not configed' % apis_conf[api])
def do_login(self):
"""login"""
main_conf = self.config.get_section_items('main')
username = main_conf['username']
password = main_conf['password']
corpcode = main_conf['corpcode']
params = {
'corpCode': corpcode,
'loginName': username,
'password': password,
'returnUrl': '',
'courseId': '',
'securityCode': '',
'continueLogin': 'true'
}
r = self.http.post(self.apis['login'], params=params)
if self.http.get_session_id():
log('user:%s login success!' % username)
else:
msg = r.get('message')
raise Exception("You maybe not login success? e:%s" % msg)
def do_heartbeat(self):
"""heartbeat"""
try:
ret = self.http.post(self.apis['heartbeat'], {'_ajax_toKen': 'os'})
log('do heartbeat, %s' % ret.get('success'))
except Exception as e:
log('do heartbeat, %s, ret:%s' % (ret.get('failure'), str(ret)))
def get_my_course(self):
"""getmycourse"""
params = {
'page.pageSize': '12',
'page.sortName': 'STUDYTIME',
'page.pageNo': '1',
'_': int(time.time())
}
try:
ret = self.http.get(self.apis['course_center'], params)
log('获取课程中心成功')
except Exception, e:
log('获取课程中心失败')
courseListRaw = ret['rows']
courseList = []
for i in courseListRaw:
if i.get('getScoreTime') is not None:
continue
courseList.append(i.get('courseId').encode('utf-8'))
log('课程中心共有%s门课程未完成' % len(courseList))
return courseList
def read_local_studyList(self, course_list):
"""优先学习study.list的课程"""
if os.path.exists(os.getcwd() + '/' + 'study.list'):
log("study.list文件存在, 将优先学习")
prefreList = []
with open('study.list') as f:
for course in f:
prefreList.append(course.strip().encode('utf-8'))
prefreList.extend(course_list)
return prefreList
else:
log("study.list文件不存在将直接学习")
return course_list
def get_course_items(self, course_id, pretty=False):
"""get course child items"""
api = self.apis['course_item'] % course_id
ret_json = self.http.get(api)
ret_json = ret_json[0]
children_list = ret_json['children']
item_list = []
for item in children_list:
if len(item['children']) == 0:
cell = {}
cell['name'] = item['text']
cell['scoId'] = item['id']
item_list.append(cell)
else:
for i in item['children']:
cell = {}
cell['name'] = i['text']
cell['scoId'] = i['id']
item_list.append(cell)
if pretty:
for i in item_list:
log('课程名: %s %s' % (i['name'], i['scoId']))
log('total items:%s' % len(item_list))
else:
return item_list
def select_score_item(self, course_id, score_id):
"""select one scoreitem and do check"""
params = {'courseId': course_id,
'scoId': score_id,
'firstLoad': 'true'}
r = self.http.post(self.apis['select_resourse'], params, json_ret=False)
try:
location = float(json.loads(r)['location'])
except:
location = 0.1
select_check_api = self.apis['select_check']
api = select_check_api % (course_id, score_id)
r = self.http.post(api, json_ret=False)
return location
def update_timestep(self):
"""update study log to server per 3min"""
ret = self.http.post(self.apis['update_timestep'])
log('do updateTimestepByUserTimmer, %s' % ret.strip('"').capitalize())
def do_save(self, course_id, score_id, location):
"""保存进度条,21tb的服务端会进行校验"""
params = {
'courseId': '', #课程的id
'scoId': '', #章节的id
'progress_measure': '100', #进度 ,这个参数已经不起作用
'session_time':'0:0:180', #在线的时间,这个参数已经不起作用
'location': '691.1', #进度条位置 秒,关键是这个
'logId': '',
'current_app_id':''
}
params.update({'courseId': course_id, 'scoId': score_id, 'location': location})
r = self.http.post(self.apis['save_progress'], params)
try:
if not r:
params_res = {'courseId': course_id, 'scoId': score_id}
r = self.http.post(self.apis['select_resourse'], params_res)
#判断完成条件之2,查询接口
if r.get('isComplete') == 'true':
return True
info = '\033[91m\tcourseProgress: %s\tcompleteRate:%s\tcompleted:%s\t\033[0m' %\
(r.get('courseProgress', '-'), r.get('completeRate'), r.get('completed', '-'))
log(info)
#判断完成条件之1,save 返回判断
if r.get('completed', '-') == 'true':
return True
except Exception as e:
log(e)
_ = '总进度:', '-', '小节:', '-'
log('总进度:\t-\t小节:\t-')
return False
def study(self, course_id):
"""study one course"""
time_step = 180
log('start course:%s' % course_id)
self.http.post(self.apis['enter_course'] % course_id, json_ret=False)
course_show_api = self.apis['course_show'] % course_id
log('url:%s' % course_show_api)
self.http.post(course_show_api, json_ret=False)
items_list = self.get_course_items(course_id)
log('*' * 50)
log('共有 %s 个子课程' % len(items_list))
for index, i in enumerate(items_list):
log('%s、%s ' % (index + 1, i['name']))
log('*' * 50)
log('begin to start...')
for index, i in enumerate(items_list):
sco_id = i['scoId']
log('begin to study:%s-%s %s' % (index + 1, i['name'], sco_id))
location = self.select_score_item(course_id, sco_id)
cnt = 0
while True:
location = location + time_step * cnt
cnt += 1
log('location: %s' % location)
self.do_heartbeat()
self.update_timestep()
ret = self.do_save(course_id, sco_id, location)
if ret:
log('%s-%s %s' % (course_id, sco_id, 'done, start next'))
break
log('*********** study %ss then go on *************' % time_step)
time.sleep(time_step)
info = '\033[92m\tDONE COURSE, url:%s\033[0m' % course_show_api
log(info)
def run(self):
"""入口"""
s = time.time()
self.do_login()
course_list = self.read_local_studyList(self.get_my_course())
for course_id in course_list:
try:
self.study(course_id)
except Exception as e:
log("exception occured, study next..")
cost = int(time.time() - s)
log('main end, cost: %ss' % cost)
if __name__ == '__main__':
study = Study()
study.run()