在之前原有功能的基础上,新增了基于 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 = driverself.entercourse_xpath = entercourse_xpathself.running = Trueself.logger = loggerdef log(self, msg):self.logger.log(msg)# 安全点击def safe_click(self, xpath):for _ in range(3):if not self.running:return Falsetry:element = WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.XPATH, xpath)))element.click()return Trueexcept 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 + sexcept: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)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]')if not Btime_str or not Etime_str:self.log("⚠️ 未检测到时间,跳转下一章节")self.click_next_chapter()continueBtime_seconds = self.time_to_seconds(Btime_str) / 0.7Etime_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 = Falsetry: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 = Noneself.driver = Noneself.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 = Trueself.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 = Noneself.log("🛑 自动执行已停止")# ---------------- 主程序 ----------------
if __name__ == "__main__":app = QApplication(sys.argv)gui = LearnInGUI()gui.show()sys.exit(app.exec_())