-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathAutoUnipus.py
More file actions
212 lines (197 loc) · 8.29 KB
/
AutoUnipus.py
File metadata and controls
212 lines (197 loc) · 8.29 KB
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
import json
import re
import time
import traceback
import uuid
from PIL import Image
from res import fetcher
from playwright.sync_api import sync_playwright
from playwright._impl._errors import TargetClosedError, TimeoutError
def auto_login(page, _user, _pwd):
print("[Tip]图形验证码需手动输入.")
login_url = "https://u.unipus.cn/user/student"
page.goto(login_url)
page.locator('[name="username"]').fill(_user)
page.locator('[name="password"]').fill(_pwd)
page.locator('[type="checkbox"]').all()[1].click()
submit = page.locator(".btn.btn-login.btn-fill")
submit.click()
print("[Tip]出现安全验证不必担心,手动认证就好了.")
page.wait_for_timeout(1000)
try:
page.wait_for_selector('#pw-captchaCode', timeout=800)
page.eval_on_selector('#pw-captchaCode', 'el => el.placeholder = "PS:请手动输入图形验证码"')
except:
return
def get_exercise(page):
must_exe = []
page.wait_for_selector(".icon-lianxi.iconfont")
exercise = page.locator(".icon-lianxi.iconfont").all()
for each in exercise:
if each.locator(".iconfont").count():
must_exe.append(each)
return must_exe
def auto_answer(page, auto_mode):
flag = False # 用于判断是否有特殊题型
# 获取题目的qid
qids = fetcher.fetch_qid(page)
if not qids:
return not flag
# qid为题目的标识符,据此进行答案获取
single_choice = ".questions--questionDefault-2XLzl.undefined"
for qid in qids:
page.wait_for_timeout(800)
total_ques = page.query_selector_all(single_choice)
answer = fetcher.fetch_ans(page, total=len(total_ques), qid=qid)
rank = 0
for ques in total_ques:
if answer[rank]["isRight"] and ques.is_visible():
choice = answer[rank]["choice"]
select = ques.wait_for_selector(f'input[value="{choice}"]')
page.wait_for_timeout(100)
try:
select.click(timeout=1500)
except TimeoutError:
return "selected"
rank += 1
else:
flag = True
break
# 点击下一页(最后一页则为"提交")
# 如果不是automode,则不进行提交
if not auto_mode and qids.index(qid) == len(qids) - 1:
break
page.locator(".submit-bar-pc--btn-1_Xvo").all()[-1].click()
# 答题结束
if flag: # 判断是否有特殊题型
if auto_mode:
page.eval_on_selector('.dialog-header-pc--dialog-header-2qsXD',
'element => element.style.fontSize = "20px"')
page.eval_on_selector('.dialog-header-pc--dialog-header-2qsXD',
'element => element.innerHTML = "PS: 存在不支持题型,本次答题不会提交"')
page.wait_for_timeout(1500)
else:
return flag
def init_page():
# 启动自带浏览器
if driver == "Chrome":
print("[Info]正在启动Chrome浏览器...")
browser = p.chromium.launch(channel="chrome", headless=False)
else:
print("[Info]正在启动Edge浏览器...")
browser = p.chromium.launch(channel="msedge", headless=False)
context = browser.new_context()
context.grant_permissions(['microphone', 'camera'])
page = context.new_page()
# 设置程序超时时限
page.set_default_timeout(300000)
# 进行登录
print("[Info]等待登录完成...")
auto_login(page, user, pwd)
page.wait_for_selector(".my_course_box")
# 绕过环境检测
page.locator(".layui-layer-btn0").click()
page.wait_for_event("popup").close()
# 设置浏览器视口大小
viewsize = page.evaluate('''() => {
return {width: window.screen.availWidth,height: window.screen.availHeight};}''')
viewsize["height"] -= 50
page.set_viewport_size(viewsize)
return page
def auto_func():
page = init_page()
title_pattern = re.compile("[0-9]+?\.[0-9]+?.+")
# 根据用户数据进行选课
class_urls = [url for url in account["class_url"] if "unipus" in url]
for class_url in class_urls:
page.goto(class_url)
# 获取"必修"课程练习
course = page.wait_for_selector(".cc_course_intro_text").text_content().strip()
print(f"[Info]当前课程:{course.splitlines(keepends=False)[0]}")
page.wait_for_selector(".icon-bixiu.iconCustumStyle.iconfont") # truly valid wait
must_exe = get_exercise(page)
# 进行必修题目的答题
for exe in must_exe:
page.reload()
page.wait_for_selector(".icon-bixiu.iconCustumStyle.iconfont")
exe.click()
if must_exe.index(exe) == 0:
page.wait_for_selector(".iKnow").click() # 点击"我知道了"
page.locator(".dialog-header-pc--close-yD7oN").click() # 关闭提示框
# 开始自动答题
flag = auto_answer(page, automode)
try:
if not flag:
head = page.wait_for_selector(".layoutHeaderStyle--menuList-Ef90e", timeout=1000).text_content()
title = re.findall(title_pattern, head)[0]
print(f"[Info]获取 <<{title}>> 答案成功!")
finally:
page.goto(class_url)
print(f"[Info]课程:{course.splitlines(keepends=False)[0]}已完成!")
if not verified:
print("[Tip]体验还不错?可以打赏作者哦~")
def assist_func():
page = init_page()
title_pattern = re.compile("[0-9]+?\.[0-9]+?.+")
print("[System]请先进入题目界面.")
while True:
input("[System]:按Enter获取答案:")
page.reload()
# 关闭提示框
try:
page.wait_for_selector(".dialog-header-pc--close-yD7oN", timeout=2500).click()
except:
print("[Error]当前为非答题页面!")
continue
# 开始获取答案
print("[Info]正在获取答案,请稍等...")
flag = auto_answer(page, automode)
if flag and flag != "selected":
print("[Error]答案获取失败,不支持当前题型!")
elif flag == "selected":
print("[Info]当前页面已作答完毕!")
else:
try:
head = page.wait_for_selector(".layoutHeaderStyle--menuList-Ef90e", timeout=1000).text_content()
title = re.findall(title_pattern, head)[0]
print(f"[Info]获取 <<{title}>> 答案成功!")
finally:
continue
if __name__ == '__main__':
try:
with open("account.json", "r", encoding="utf-8") as f:
account = json.loads(f.read())
user = account["username"].strip()
pwd = account["password"].strip()
driver = account["Driver"].strip()
automode = account["Automode"]
key = account["Key"].strip()
verified = fetcher.verify_key(key)
print("[Tip]目前只支持单选题作答!")
print("===== Runtime Log =====")
with sync_playwright() as p:
if automode:
print("[System]Automode active.")
auto_func()
print("所有课程已完成!!")
input("按Enter退出程序...")
else:
print("[System]Assistmode active.")
assist_func()
except TargetClosedError:
print("[Error]糟糕,网页关闭了!")
except TimeoutError:
print("[Error]程序长时间无响应,自动退出...")
except FileNotFoundError:
print("[Error]程序缺失依赖文件,请重新安装程序!")
except Exception as e:
print(f"[Error]{e}")
if type(e) == KeyError:
print("[Tip]可能是account文件的配置出错")
log = traceback.format_exc()
with open("log.txt", "w", encoding="utf-8") as doc:
doc.write(log)
print("[Info]错误日志已保存至:log.txt")
print("[Tip]系统出错,要不重启一下?")
finally:
time.sleep(1.5)