大战升学e网通之完全胜利

特别鸣谢:ChatGPT、Deepseek、提供精神支持的同学、提供技术支持的大牛们

千夫诺诺,不如一士谔谔!

不知道升学e网通这种祸国殃民、荼毒生灵、蠹国害民的东西是怎么活这么久的,真是流毒无穷,伤害了无数学生的心灵。

和e网通的初见是在2023年的夏天。

夏日。燥热。沉闷的空气中暗流涌动。根据学校发的通知下载了这个名字叫“升学e网通”的软件。

充满活力的橙色配上忧郁的蓝色环绕,便是这个b软件的logo。

望着App Store中满屏的差评,我不禁陷入了沉思。

在家长的驱动下,我打开了这个b软件。

哇,史一样的UI设计,史一样的操作逻辑

嗯,学校让我们用这个肯定也有他的理由对吧。

这一定是怎么说来着,败絮其外,金玉其中。

结果一看网课内容,更是史

好吧,什么因式分解,讲了半小时,属实是听得疲倦了,也没有听出个所以然。

遂去知乎检索,5分钟,哇学会了。

这种低质网课看来看去,看得颓唐,便邀请其进行斗法!

Round 1 一边玩一边挂机

哈哈,我觉得这真是太好了。

我在前台打CS,后台挂网课,打完一把刚好手动切换一集,不错不错。

打完后。

啊?

狡猾!狡猾!还有挂机检测!

Round 1 完败

Round 2 不管了,开摆!

呵呵,我爱看不看,你管得着吗!

然后就被可爱班主任告知家长了。

狡猾!狡猾!还有场外援助!

Round 2 完败

Round 3 另请高人

听说隔壁yzzx有巨佬有自动挂课脚本。

呀,恰好认识这个巨佬!

赶紧去说好话,发了账号密码,坐享其成。

半小时后。

啊?效率这么高?全部搞完了!

太厉害了。

Round 3 胜

Round 4 “不是哥们这怎么过不了挂机检测啊”

又一年寒假,想着再去找巨佬开科技,不料巨佬临时有事,让我先等等。

这我可不能坐以待毙,干脆自己行动。

上Github找了关于ewt的项目。

发现一个很巨的项目已经停止维护了,并找到了其作者和ewt大战记录。

看得我热血沸腾,顺着issue里的蛛丝马迹

找到了另一位神犇用Python+Selenuim开发的一个项目

虽然没有当时50倍速播放的超标特技,但是也能实现自动化挂完网课。

不错,下载下来调教一番!

然后发现。呃。这我怎么打开半天连我的Chrome都打不开?

于是加了打开指定路径 Chrome

1
chrome_options.binary_location = "C:/example.exe"

噢噢这下一下子就打开了!

然后发现怪怪的,一看又崩了。仔细翻找发现,这ewt更新了,有个地方需要手动点一下。

好了,终于开始刷课了,开一把CS先!

打完一看,诶?怎么又崩了??这不对吧,然后请教了下大神ShaPaper

他教我使用了python中的try和except,完美的解决了问题。

于是就这么挂了一天。

结果回望战果时发现,嗯?怎么挂机检测全都没通过?

“不是哥们这怎么过不了挂机检测啊!”

Round 4 败

Round 5 终局之战

嗯,中间出去旅了个游,回来再战一番!

注意到原程序中挂机检测的按钮叫做什么skip-action,好,我去看看这个按钮是怎么个事

等了半天终于等来了挂机检测,哇,赶紧F12看看!怎么回事,根本找不到这个元素啊!

一点一点翻了半天,才发现这个元素名字叫做btn-3LStS

这看起来像是一个随机生成的元素名。

查询悉数资料发现,可以通过按钮名字来翻找元素名,再进行点击。

不过调试许久,都未有进展。

恰好想再看看名称生成规律,于是重复了上述步骤。

诶不对,怎么这还叫btn-3LStS啊?

?????????

好小子,骗我是吧!

解决了该问题,不错,可以接着挂了。

挂着挂着,这怎么叫我提交政治试卷啊!

这bug也太多了吧,不知道原作者当时是怎么跑起来的。

又写了个简易脚本提交完了所有试卷,虽然是交白卷(开学危

这下终于完美运行了!

呼~

画上一个圆满的句号。

Round 5 完胜!

一些后话

希望这是最后一战了,隔壁的几个学校都公投取消了这个恶心的e网通。

不错,自己的第一个Python微型项目也算完成任务楽!

把这个项目push到了GitHub上,欢迎大家Star!

噢对了好像还有信息作业要写来着…那么就不写了!

开学直接把这个项目发给亲爱的信息老师,让他来Fork Fork嘿嘿。

这就算我的信息寒假作业啦!

最后放上项目代码

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
import logging
import time

from selenium import webdriver
from selenium.common.exceptions import JavascriptException, TimeoutException
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options


#输入用户的账户名称和密码

USER = "username"
PASS = "userpassword"


def switch_to_new_window(driver):
"""切换到最新打开的窗口"""
new_handle = driver.window_handles[-1]
logging.info(f"切换到新页面: {new_handle}")
driver.switch_to.window(new_handle)

def get_all_progress(driver):
"""等待并获取总完成度文本"""
try:
progress_element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located(
(By.CSS_SELECTOR, "#rc-tabs-0-panel-1 > section > section > section > span:nth-child(1) > span")
)
)
return progress_element.text
except TimeoutException:
logging.error("获取完成度超时")
return ""

def login(driver):
"""完成登录操作"""
logging.info("尝试登录...")
user_field = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "login__password_userName"))
)
user_field.send_keys(USER)
pass_field = driver.find_element(By.ID, "login__password_password")
pass_field.send_keys(PASS)
sub_btn = driver.find_element(By.CLASS_NAME, "ant-btn-primary")
sub_btn.click()

def navigate_to_vacation(driver):
"""点击‘我的假期’后关闭当前窗口,并切换到新窗口"""
vacation_link = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.LINK_TEXT, "我的假期"))
)
vacation_link.click()
driver.close()
switch_to_new_window(driver)

def click_primary_button(driver):
"""等待并点击页面上的主要按钮"""
primary_btn = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CLASS_NAME, "ant-btn-primary"))
)
primary_btn.click()

def wait_for_video_completion(driver, lesson_name, action_chains):
"""处理视频播放,直至视频播放完毕"""
try:
play_btn = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CLASS_NAME, "vjs-big-play-button"))
)
play_btn.click()
except TimeoutException:
logging.error("找不到播放按钮")

# 设置播放速度和静音
driver.execute_script('document.querySelector("video").playbackRate = 2')
driver.execute_script('document.querySelector("video").muted = true')
video = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "video"))
)
while True:
# 挂机检测部分
for cls in ["btn-3LStS"]:
elements = driver.find_elements(By.CLASS_NAME, cls)
if elements:
action_chains.click(elements[0]).perform()
logging.info(f"处理 {cls} 检测")
# 获取视频进度
try:
current_time = float(video.get_attribute("currentTime"))
duration = float(video.get_attribute("duration"))
except Exception as e:
logging.error("读取视频属性失败")
break
logging.info(f"视频进度: {current_time}/{duration}")
time.sleep(5)
if current_time >= duration:
logging.info(f"{lesson_name} | 已完成")
driver.close()
switch_to_new_window(driver)
break

def process_lessons(driver, action_chains):
"""处理当前课程中的所有视频/学习任务"""
try:
container = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "ant-spin-container"))
)
lesson_container = container.find_element(By.XPATH, "./*")
lesson_list = lesson_container.find_elements(By.XPATH, "./*")
except Exception as e:
logging.error("获取课程列表失败")
return

# 若最后一个元素为“加载更多”,点击后重新获取列表
if lesson_list and lesson_list[-1].text == "加载更多":
logging.info("发现更多课程,重新获取...")
action_chains.click(lesson_list[-1]).perform()
lesson_list = container.find_element(By.XPATH, "./*").find_elements(By.XPATH, "./*")[:-1]
elif lesson_list:
lesson_list.pop() # 去掉多余项

for raw_lesson in lesson_list:
logging.info(f"总进度: {get_all_progress(driver)}")
action_chains.move_to_element(raw_lesson).perform()
lessons = raw_lesson.find_elements(By.XPATH, "./*")
if not lessons or len(lessons) < 2:
continue
# 获取课程名称和状态
lesson_name = lessons[0].find_element(By.XPATH, "./*").text
lesson_status = (lessons[1].find_elements(By.XPATH, "./*")[1].text
if lessons[1].text != "已完成" else "已完成")
logging.info(f"{lesson_name} | {lesson_status}")
if lesson_status == "去学习":
action_chains.click(lessons[0]).perform()
WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2))
switch_to_new_window(driver)
# 根据当前URL判断是否为自动完成的页面
if ("xinli.ewt360.com" in driver.current_url or
"web.ewt360.com/spiritual-growth" in driver.current_url):
time.sleep(5)
logging.info(f"{lesson_name} | 已完成")
driver.close()
switch_to_new_window(driver)
else:
time.sleep(1)
wait_for_video_completion(driver, lesson_name, action_chains)

def main():
logging.basicConfig(
format="[%(asctime)s] %(filename)s(line:%(lineno)d) - %(levelname)s: %(message)s",
level=logging.INFO, datefmt="%Y/%m/%d %H:%M:%S"
)
logging.info("正在启动Chrome...")
chrome_options = Options()
# 指定 Chrome 可执行文件的完整路径
chrome_options.binary_location = "C:/example.exe"
driver = webdriver.Chrome(options=chrome_options)
driver.maximize_window()
action_chains = ActionChains(driver)

driver.get("https://teacher.ewt360.com/")
logging.info(driver.title)
driver.implicitly_wait(10)

login(driver)
navigate_to_vacation(driver)
time.sleep(5) # 等待新页面加载
click_primary_button(driver)
logging.info("获取总完成度...")
time.sleep(10) # 可考虑进一步用WebDriverWait优化
progress = get_all_progress(driver)
sProgress = progress.split("/")
if sProgress[0] == sProgress[1]:
logging.info("所有课程已完成,按下回车退出")
input()
else:
logging.info("寻找左滑按钮...")
time.sleep(5)
try:
left_btn = driver.find_element(By.CLASS_NAME, "left-icon")
except Exception as e:
logging.error("找不到左滑按钮")
left_btn = None

start = True
turn_left = False
confirm_quit = False
while True:
if turn_left and left_btn:
try:
action_chains.click(left_btn).perform()
except JavascriptException:
logging.info("页面最左")
time.sleep(10)
turn_left = False
start = True
if start:
logging.info("获取完成度...")
time.sleep(1)
try:
swiper_box = driver.find_element(By.CLASS_NAME, "swiper-item-box")
data_container = swiper_box.find_element(By.XPATH, "./*")
data_items = data_container.find_elements(By.XPATH, "./*")
except Exception as e:
logging.error("获取数据失败")
break
for index, item in enumerate(data_items):
progress = get_all_progress(driver)
sProgress = progress.split("/")
if sProgress[0] == sProgress[1]:
logging.info("已完成所有课程!")
logging.info("回车退出")
start = False
confirm_quit = True
input()
break
if not item.text.strip():
continue
try:
pdata = item.find_element(By.TAG_NAME, "div")
pdata2 = item.find_element(By.TAG_NAME, "p")
except Exception:
continue
day = pdata.text
progress_text = pdata2.text
parts = progress_text.split("/")
if parts[0] != parts[1]:
logging.info(f"{day}的进度为{progress_text}")
action_chains.click(item).perform()
time.sleep(1)
process_lessons(driver, action_chains)
else:
# 如果下一个元素为空,则右滑
if index + 1 < len(data_items) and not data_items[index + 1].text.strip():
logging.info("右滑")
try:
right_btn = driver.find_element(By.CLASS_NAME, "right-icon")
action_chains.click(right_btn).perform()
except Exception as e:
logging.error("找不到右滑按钮")
time.sleep(3)
break
elif confirm_quit:
break
driver.quit()

if __name__ == '__main__':
main()