首页 > Python资料 博客日记
2023智慧树刷课脚本 基于Python selenium的自动化刷智慧树程序 [有免安装版]
2024-03-22 04:00:07Python资料围观378次
2024/3/20 rebuild-3.9.1 更新
-
修复点击下一集时出现"卡死/闪退"的问题.
经过测试发现是网站官方播放器的Bug, 当下一集是不含视频的假标签时,点击下一集会陷入卡死状态; 通过调整切换下一集的程序逻辑已经适配此问题。
(可能有时会出现不稳定情况, 但应该不影响正常使用)
Autovisor
智慧树视频课辅助工具,开启挂机摸鱼时代~
新学期必备干货, 建议收藏备用 !!
项目主页:CXRunfree/Autovisor(github.com) (不妨点个star吧)
程序介绍
这是一个可无人监督的自动化程序,由Python和JavaScript编写而成。相对于油猴脚本,本程序可有效防止被网页检测。
核心原理是使浏览器模拟用户的点击操作, 不会导致封号等问题
程序功能
-
可以快速登录
-
自动播放和切换下一集
-
跳过弹窗和弹出的题目
-
自动静音、调整1.5倍速和流畅画质
-
检测视频是否暂停并续播 (不用担心视频意外暂停了~)
-
检测当前学习进度并后台实时更新
-
根据当前时间自动设置背景颜色(白昼/暗夜)
- 加入了定时模拟鼠标滑动功能 (减少被检测到的概率)
- 完成章节时将提示已刷课时长
使用须知(重要 !!)
1.请确保系统为windows10及以上
- 默认启动Edge(win10以上系统会自带);
- 请确保Edge或Chrome安装在系统默认位置;
2.文件夹内有 account.json文件(可能没显示.json后缀名),请用文本编辑器打开;
3.填写配置文件
- “User”:输入你的 账户名;
- “Password”:输入你的 密码;
- “Driver”:指定启动的 浏览器(可选Chrome);
- “Url”:输入网课的 具体网址,保存后关闭,例如:
注意:
-
此脚本仅支持共享课视频, 网址格式与需下面一致, 填入时请看仔细;
-
只能使用英文标点
4.运行程序,会自动打开浏览器,登录界面的滑块验证请手动完成,进入网课界面后就可以自动刷课了 !
发行版下载:
Github: Releases · CXRunfree/Autovisor (github.com) (留下一个免费的 star吧?)
网盘备用: [蓝奏云] Autovisor-for-windows 密码:492l
为便于阅读, 源码已放在文末
如有疑问,可以在评论区留言, 每条留言作者都会认真看的 !
(报错问题请附上报错信息,在log.txt文件内)
常见问题
1.为什么会出现一个命令行黑框?
- 这是程序运行的后台,你可以查看当前运行的状态
2.为什么网页一片空白/无法加载课程界面,一段时间后程序就退出了?
-
大概率你没有在account文件里填入课程的网址;
此外从登录完成后到进入课程界面的过程不需要鼠标点击
3.为什么运行程序只出现后台却没出现浏览器界面?
- 只要后台未异常退出就不必担心; 如果出错可能是你的浏览器安装路径有问题
已知Bug:
- 长时间挂机有概率弹出人机验证, 如果1.5h内未通过验证, 程序将自动结束进程;
-
若出现其他异常崩溃,请在Github提交issue并附上日志文件log.txt的信息;
碎碎念:
觉得体验还不错? 来给项目发电支持一下吧~!
(其实作者也要吃饭的 ^-^)
注意:本程序只可用于学习和研究计算机原理(你懂的)
还等什么? 快开始愉快的刷课吧~ !
源代码
#encoding=utf-8
import re
import traceback
import json
import time
from json import JSONDecodeError
from playwright.sync_api import sync_playwright
from playwright._impl._errors import TargetClosedError, TimeoutError
# constants
login_url = "https://passport.zhihuishu.com/login"
# Xpath
option1 = '//*[@id="playTopic-dialog"]/div/div[2]/div/div[1]/div/div/div[2]/ul/li[1]/div[2]'
option2 = '//*[@id="playTopic-dialog"]/div/div[2]/div/div[1]/div/div/div[2]/ul/li[2]/div[2]'
# javascript
# 登录
login_js = '''document.getElementsByClassName("wall-sub-btn")[0].click();'''
block_js = '''return document.getElementsByClassName("yidun_jigsaw")[0].src'''
bg_js = '''return document.getElementsByClassName("yidun_bg-img")[0].src'''
# 弹窗
pop_js = '''document.getElementsByClassName("iconfont iconguanbi")[0].click();'''
# pop2_js = '''document.evaluate('//*[@id="app"]/div/div[1]/div[1]/span/a',document).iterateNext().click();'''
# 其他
night_js = '''document.getElementsByClassName("Patternbtn-div")[0].click()'''
def auto_login(_user, _pwd):
if not user or not pwd:
raise UserWarning
page.goto(login_url)
page.locator('#lUsername').fill(_user)
page.locator('#lPassword').fill(_pwd)
page.wait_for_timeout(500)
page.evaluate(login_js)
def init_page():
# 启动自带浏览器
if driver == "Chrome":
print("正在启动Chrome浏览器...")
browser = p.chromium.launch(channel="chrome", headless=False)
else:
print("正在启动Edge浏览器...")
browser = p.chromium.launch(channel="msedge", headless=False)
context = browser.new_context()
page = context.new_page()
# 设置程序超时时限
page.set_default_timeout(300 * 1000 * 1000)
# 设置浏览器视口大小
viewsize = page.evaluate('''() => {
return {width: window.screen.availWidth,height: window.screen.availHeight};}''')
viewsize["height"] -= 50
page.set_viewport_size(viewsize)
return page
def optimize_page():
# 关闭学习须知
page.evaluate(pop_js)
# 根据当前时间切换夜间模式
hour = time.localtime().tm_hour
if hour >= 18 or hour < 7:
page.wait_for_selector(".Patternbtn-div")
page.evaluate(night_js)
try:
# 关闭上方横幅
page.wait_for_selector(".exploreTip", timeout=500)
page.query_selector('a:has-text("不再提示")').click()
finally:
return
def get_lesson_name():
title_ele = page.wait_for_selector("#lessonOrder")
page.wait_for_timeout(500)
title_ = title_ele.get_attribute("title")
return title_
def move_mouse():
page.wait_for_selector(".videoArea", state="attached", timeout=10000)
elem = page.locator(".videoArea")
elem.hover()
pos = elem.bounding_box()
if not pos:
return
# 计算移动的目标位置
target_x = pos['x'] + 30
target_y = pos['y'] + 30
page.mouse.move(target_x, target_y)
def get_progress():
curt = "0%"
move_mouse()
cur_play = page.query_selector(".current_play")
progress = cur_play.query_selector(".progress-num")
if not progress:
finish = cur_play.query_selector(".time_icofinish")
if finish:
curt = "100%"
else:
curt = progress.text_content()
return curt
def check_play():
playing = page.query_selector(".pauseButton")
if not playing:
canvas = page.wait_for_selector(".videoArea", state="attached")
move_mouse()
canvas.click()
return False
else:
return True
def video_optimize():
move_mouse()
page.wait_for_selector(".volumeBox").click() # 设置静音
page.wait_for_selector(".definiBox").hover() # 切换流畅画质
low_quality = page.wait_for_selector(".line1bq")
low_quality.hover()
low_quality.click()
page.wait_for_selector(".speedBox").hover() # 切换1.5倍速
max_speed = page.wait_for_selector(".speedTab15")
max_speed.hover()
max_speed.click()
def skip_question():
try:
page.wait_for_selector(".topic-item", timeout=2000)
choices = page.locator(".topic-item").all()
choices[0].click()
choices[1].click()
page.wait_for_timeout(500)
page.locator(".btn").all()[3].click()
except TimeoutError:
return
def main_function():
# 进行登录
print("等待登录完成...")
auto_login(user, pwd)
# 等待完成滑块验证,已设置5min等待时间
page.wait_for_selector(".wall-main", state="hidden")
# 遍历所有课程,加载网页
for course_url in urls:
id_pat = re.compile("recruitAndCourseId=[a-zA-Z0-9]+")
matched = re.findall(id_pat, course_url)
if not matched:
print(f"\"{course_url.strip()}\"\n不是一个有效网址,即将自动跳过!")
continue
print("开始加载播放页...")
page.set_default_timeout(90 * 60 * 1000)
page.goto(course_url)
page.wait_for_selector(".studytime-div")
# 关闭弹窗,优化页面体验
optimize_page()
# 获取当前课程名
course_title = page.wait_for_selector(".source-name").text_content()
print(f"当前课程:<<{course_title}>>")
page.set_default_timeout(5000)
start_time = time.time() # 记录开始学习时间
page.wait_for_selector(".clearfix.video", state="attached")
all_class = page.locator(".clearfix.video").all()
for each in all_class:
try:
page.wait_for_selector(".current_play", state="attached")
each.click()
page.wait_for_timeout(1000)
# 获取课程小节名
title = get_lesson_name()
print("正在学习:%s" % title)
# 根据进度条判断播放状态
curtime = get_progress()
if curtime != "100%":
check_play() # 开始播放
video_optimize() # 对播放页进行初始化配置
while curtime != "100%":
skip_question() # 跳过中途弹题(只支持选择题)
playing = check_play()
curtime = get_progress()
if not playing and curtime != "100%":
print("当前小节未刷满,将继续播放..")
print("正在学习:%s" % title)
else:
print('完成进度:%s' % curtime)
page.wait_for_timeout(1000)
time_period = (time.time() - start_time) / 60
if time_period >= 1: # 每完成一节提示一次时间
print("本次课程已学习:%.1f min" % time_period)
# 如果当前小节是最后一节代表课程学习完毕
class_name = all_class[-1].get_attribute('class')
if "current_play" in class_name:
print("已学完本课程全部内容!")
print("==" * 10)
break
else: # 否则为完成当前课程的一个小节
print(f"\"{title}\" Done !")
except TimeoutError:
if page.query_selector(".yidun_modal__title"):
print("检测到安全验证,正在等待手动完成...")
page.wait_for_selector(".yidun_modal__title", state="hidden", timeout=90 * 60 * 1000)
elif page.query_selector(".topic-item"):
skip_question()
if __name__ == "__main__":
print("项目作者:CXRunfree 版权所有")
print("===== Runtime Log =====")
try:
print("正在载入数据...")
with open("account.json", "r", encoding="utf-8") as f:
account = json.loads(f.read())
user = account["User"].strip()
pwd = account["Password"].strip()
driver = account["Driver"].strip()
urls = account["Url"]
if not isinstance(urls, list):
print('[Error]"Url"项格式错误!')
raise KeyError
with sync_playwright() as p:
page = init_page()
main_function()
print("==" * 10)
print("所有课程学习完毕!")
input()
except Exception as e:
if isinstance(e, JSONDecodeError):
print("[Error]account文件内容有误!")
elif isinstance(e, KeyError):
print("[Error]可能是account文件的配置出错!")
elif isinstance(e, UserWarning):
print("[Error]是不是忘记填账号密码了?")
elif isinstance(e, FileNotFoundError):
print("[Error]程序缺失依赖文件,请重新安装程序!")
elif isinstance(e, TargetClosedError):
print("[Error]糟糕,网页关闭了!")
elif isinstance(e, TimeoutError):
print("[Error]网页长时间无响应,自动退出...")
else:
print(f"[Error]{e}")
with open("log.txt", "w", encoding="utf-8") as doc:
doc.write(traceback.format_exc())
print("错误日志已保存至:log.txt")
print("系统出错,要不重启一下?")
input()
标签:
相关文章
最新发布
- 光流法结合深度学习神经网络的原理及应用(完整代码都有Python opencv)
- Python 图像处理进阶:特征提取与图像分类
- 大数据可视化分析-基于python的电影数据分析及可视化系统_9532dr50
- 【Python】入门(运算、输出、数据类型)
- 【Python】第一弹---解锁编程新世界:深入理解计算机基础与Python入门指南
- 华为OD机试E卷 --第k个排列 --24年OD统一考试(Java & JS & Python & C & C++)
- Python已安装包在import时报错未找到的解决方法
- 【Python】自动化神器PyAutoGUI —告别手动操作,一键模拟鼠标键盘,玩转微信及各种软件自动化
- Pycharm连接SQL Sever(详细教程)
- Python编程练习题及解析(49题)
点击排行
- 版本匹配指南:Numpy版本和Python版本的对应关系
- 版本匹配指南:PyTorch版本、torchvision 版本和Python版本的对应关系
- Python 可视化 web 神器:streamlit、Gradio、dash、nicegui;低代码 Python Web 框架:PyWebIO
- 相关性分析——Pearson相关系数+热力图(附data和Python完整代码)
- Anaconda版本和Python版本对应关系(持续更新...)
- Python与PyTorch的版本对应
- Windows上安装 Python 环境并配置环境变量 (超详细教程)
- Python pyinstaller打包exe最完整教程