上海应用大学网课自动化学习脚本(基于Python selenium)代码重构为GUI界面 —— 技术笔记
在之前原有功能的基础上,新增了基于 PyQt5 的图形化用户界面(GUI),提升了操作体验和可视化程度,主要功能包括:
1. 日志显示区
界面上方新增一个 日志窗口(QTextEdit)。
程序运行过程中产生的所有提示、执行进度、错误信息都会实时输出到日志区。
日志会自动滚动到最新位置,方便用户查看。
2. 控制区(三个主要组件)
输入框(QLineEdit)
用于输入或修改 Entercourse 的 XPath。
这个 XPath 是进入具体课程的关键定位符,用户可根据需要手动修改。
“开始自动执行”按钮(QPushButton)
点击后会自动启动 Edge 浏览器并打开指定学习网站。
程序自动完成以下步骤:
切换到密码登录页面
自动输入账号密码并登录
点击“查看全部”进入课程列表
使用输入框中的 XPath 定位并进入指定课程
开始播放课程视频,并进入自动刷课逻辑
“关闭浏览器”按钮(QPushButton)
点击后会停止自动执行线程,并关闭当前 Edge 浏览器。
保证不会因为强制关闭而导致残留的后台浏览器进程。
3. 备注说明区
在控制区按钮下方新增了一行 说明性文本(QLabel):
“备注: Entercourse XPath 为应刷课程的 XPath”
主要是帮助用户理解输入框的用途,避免误操作。
重构后代码如下:
import sys
import time
import threading
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QTextEdit, QLineEdit, QLabel
from PyQt5.QtCore import pyqtSignal, QObject
from selenium import webdriver
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.common.exceptions import StaleElementReferenceException
#***********************************GUI开发版:上海应用大学网课自动刷视频***********************************
# ---------------- 日志信号 ----------------
class Logger(QObject):
log_signal = pyqtSignal(str)
def __init__(self):
super().__init__()
def log(self, msg):
self.log_signal.emit(msg)
# ---------------- Selenium 自动执行线程 ----------------
class AutoPlayThread(threading.Thread):
def __init__(self, driver, entercourse_xpath, logger):
super().__init__()
self.driver = driver
self.entercourse_xpath = entercourse_xpath
self.running = True
self.logger = logger
def log(self, msg):
self.logger.log(msg)
# 安全点击
def safe_click(self, xpath):
for _ in range(3):
if not self.running:
return False
try:
element = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.XPATH, xpath))
)
element.click()
return True
except StaleElementReferenceException:
time.sleep(1)
return False
# 安全获取文本
def safe_get_text(self, xpath):
for _ in range(3):
if not self.running:
return ""
try:
element = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.XPATH, xpath))
)
return element.text.strip()
except StaleElementReferenceException:
time.sleep(1)
return ""
def time_to_seconds(self, time_str):
try:
h, m, s = map(int, time_str.split(":"))
return h*3600 + m*60 + s
except:
return 0
# ---------------- 自动化功能 ----------------
def jumpPasswd(self):
if self.safe_click('//*[@id="app"]/div/div/div/div[1]/div[2]/div/div[1]/div[1]/div/label[2]'):
self.log("✅ 开始验证码验证")
else:
self.log("❌ 验证码验证失败")
def login(self):
try:
username_input = self.driver.find_element(By.XPATH,
'//*[@id="app"]/div/div/div/div[1]/div[2]/div/div[1]/div[2]/div/form/div[1]/div/div/input')
password_input = self.driver.find_element(By.XPATH,
'//*[@id="app"]/div/div/div/div[1]/div[2]/div/div[1]/div[2]/div/form/div[2]/div/div[1]/input')
login_button = self.driver.find_element(By.XPATH,
'//*[@id="app"]/div/div/div/div[1]/div[2]/div/div[1]/div[2]/div/div/div/button')
time.sleep(1)
username_input.send_keys("15346111559")
password_input.send_keys("Xzl19980216")
login_button.click()
time.sleep(3)
self.log("✅ 登录成功")
except Exception as e:
self.log(f"❌ 登录失败: {e}")
def Viewall(self):
if self.safe_click('//*[@id="studentHomeStep4"]/div/div[1]/div/a'):
self.log("✅ 进入查看全部成功")
time.sleep(2)
else:
self.log("❌ 进入查看全部失败")
def Entercourse(self):
if self.safe_click(self.entercourse_xpath):
self.log("✅ 进入课程成功")
time.sleep(2)
else:
self.log("❌ 进入课程失败")
def ClicklearnVideo(self):
try:
self.driver.switch_to.window(self.driver.window_handles[-1])
if self.safe_click('//*[@id="app"]/div/div[1]/div[2]/div[1]/div/div[2]/div/div[2]/div/div/div[2]/div/div/div[2]/div/div[1]/div[2]/div[2]/div[1]/button'):
self.log("🎬 视频开始播放")
time.sleep(2)
else:
self.log("❌ 播放视频失败")
except Exception as e:
self.log(f"❌ 播放视频失败: {e}")
def click_next_chapter(self):
if self.safe_click('//*[@id="app"]/div/div[1]/div[1]/div[3]/div[3]/button'):
self.log("➡️ 跳转到下一章节")
time.sleep(5)
self.ClicklearnVideo()
else:
self.log("❌ 无法点击“下一章节”")
def auto_play_videos(self):
while self.running:
try:
time.sleep(5)
element = self.driver.find_element(By.CSS_SELECTOR, "div.section-content-progress.align-right")
text = element.text
print("获取到的值:", text)
if text == "0 / 0":
print("⚠️ 当前章节无可播放内容,跳转到下一章节")
self.click_next_chapter()
continue
#获取应观看时间和已观看时间
Btime_str = self.safe_get_text(
'//*[@id="app"]/div/div[1]/div[2]/div[1]/div/div[2]/div/div[2]/div/div/div[3]/div[2]/span[2]')
Etime_str = self.safe_get_text(
'//*[@id="app"]/div/div[1]/div[2]/div[1]/div/div[2]/div/div[2]/div/div/div[3]/div[2]/span[3]')
Btime_seconds = self.time_to_seconds(Btime_str) / 0.7
Etime_seconds = self.time_to_seconds(Etime_str)
self.log(f"🎞 观看时长应达到: {Btime_seconds}秒")
self.log(f"🎞 当前已观看: {Etime_seconds}秒")
if Etime_seconds >= Btime_seconds:
self.log("✅ 视频播放完成,准备跳转下一章")
self.click_next_chapter()
except Exception as e:
self.log(f"❌ 播放出错: {e}")
self.driver.refresh()
time.sleep(3)
self.ClicklearnVideo()
def stop(self):
self.running = False
try:
self.driver.quit()
self.log("🛑 浏览器已关闭")
except:
pass
# ---------------- GUI 界面 ----------------
class LearnInGUI(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("上海应用大学网课自动刷视频")
self.setGeometry(100, 100, 800, 600)
self.thread = None
self.driver = None
self.logger = Logger()
self.logger.log_signal.connect(self.log)
layout = QVBoxLayout()
self.setLayout(layout)
# 日志显示
self.log_text = QTextEdit()
self.log_text.setReadOnly(True)
layout.addWidget(self.log_text)
# 控制区域
control_layout = QHBoxLayout()
control_layout.addWidget(QLabel("Entercourse XPath:"))
self.entercourse_input = QLineEdit('//*[@id="app"]/div/div[2]/div[1]/div[2]/div[1]/div[1]/div[2]/div[2]/a')
control_layout.addWidget(self.entercourse_input)
self.start_btn = QPushButton("开始自动执行")
self.start_btn.clicked.connect(self.start_auto)
control_layout.addWidget(self.start_btn)
self.stop_btn = QPushButton("关闭浏览器")
self.stop_btn.clicked.connect(self.stop_browser)
control_layout.addWidget(self.stop_btn)
layout.addLayout(control_layout)
# **新增一行文本备注**
self.xpath_note = QLabel("备注: Entercourse XPath为应刷课程的 XPath")
layout.addWidget(self.xpath_note)
def log(self, msg):
self.log_text.append(msg)
self.log_text.verticalScrollBar().setValue(self.log_text.verticalScrollBar().maximum())
def start_auto(self):
if self.thread is None:
edge_options = webdriver.EdgeOptions()
edge_options.use_chromium = True
self.driver = webdriver.Edge(options=edge_options)
self.driver.get("https://www.learnin.com.cn/#/login")
time.sleep(5)
entercourse_xpath = self.entercourse_input.text().strip()
self.thread = AutoPlayThread(self.driver, entercourse_xpath, self.logger)
# 按顺序执行初始化任务
self.thread.jumpPasswd()
self.thread.login()
self.thread.Viewall()
self.thread.Entercourse()
self.thread.ClicklearnVideo()
# 启动自动播放线程
threading.Thread(target=self.thread.auto_play_videos, daemon=True).start()
self.log("🚀 自动执行开始")
def stop_browser(self):
if self.thread:
self.thread.stop()
self.thread = None
self.log("🛑 自动执行已停止")
# ---------------- 主程序 ----------------
if __name__ == "__main__":
app = QApplication(sys.argv)
gui = LearnInGUI()
gui.show()
sys.exit(app.exec_())

浙公网安备 33010602011771号