当前位置:   article > 正文

2023智慧树刷课脚本 基于Python selenium的自动化刷智慧树程序 [有免安装版]_智慧树刷客

智慧树刷客
2024/3/15 rebuild-3.8 更新
  • 优化了进度条判定逻辑, 当右侧圆环进度为100%时判定为已完成

  • 播放时自动设置为1.5倍速并切换流畅画质

此次更新应当能解决"切换小节时提示课程已完成"的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:

  • 长时间挂机有概率弹出人机验证, 如果一个半小时内未通过验证, 程序将自动结束进程;
  • 若出现其他异常崩溃,请在Github提交issue并附上日志文件log.txt的信息;

碎碎念:

觉得体验还不错? 来给项目发电支持一下吧~! 

(其实作者也要吃饭的 ^-^)

注意:本程序只可用于学习和研究计算机原理(你懂的)

  还等什么? 快开始愉快的刷课吧~ !

源代码
  1. # encoding=utf-8
  2. import asyncio
  3. import os
  4. import re
  5. import traceback
  6. import json
  7. import time
  8. from json import JSONDecodeError
  9. from playwright.sync_api import sync_playwright
  10. from playwright._impl._errors import TargetClosedError, TimeoutError
  11. # constants
  12. login_url = "https://passport.zhihuishu.com/login"
  13. # Xpath
  14. option1 = '//*[@id="playTopic-dialog"]/div/div[2]/div/div[1]/div/div/div[2]/ul/li[1]/div[2]'
  15. option2 = '//*[@id="playTopic-dialog"]/div/div[2]/div/div[1]/div/div/div[2]/ul/li[2]/div[2]'
  16. # javascript
  17. # 登录
  18. login_js = '''document.getElementsByClassName("wall-sub-btn")[0].click();'''
  19. block_js = '''return document.getElementsByClassName("yidun_jigsaw")[0].src'''
  20. bg_js = '''return document.getElementsByClassName("yidun_bg-img")[0].src'''
  21. # 弹窗
  22. pop_js = '''document.getElementsByClassName("iconfont iconguanbi")[0].click();'''
  23. # pop2_js = '''document.evaluate('//*[@id="app"]/div/div[1]/div[1]/span/a',document).iterateNext().click();'''
  24. # 其他
  25. night_js = '''document.getElementsByClassName("Patternbtn-div")[0].click()'''
  26. def auto_login(_user, _pwd):
  27. if not user or not pwd:
  28. raise UserWarning
  29. page.goto(login_url)
  30. page.locator('#lUsername').fill(_user)
  31. page.locator('#lPassword').fill(_pwd)
  32. page.wait_for_timeout(500)
  33. page.evaluate(login_js)
  34. def init_page():
  35. # 启动自带浏览器
  36. if driver == "Chrome":
  37. print("正在启动Chrome浏览器...")
  38. browser = p.chromium.launch(channel="chrome", headless=False)
  39. else:
  40. print("正在启动Edge浏览器...")
  41. browser = p.chromium.launch(channel="msedge", headless=False)
  42. context = browser.new_context()
  43. page = context.new_page()
  44. # 设置程序超时时限
  45. page.set_default_timeout(300 * 1000 * 1000)
  46. # 设置浏览器视口大小
  47. viewsize = page.evaluate('''() => {
  48. return {width: window.screen.availWidth,height: window.screen.availHeight};}''')
  49. viewsize["height"] -= 50
  50. page.set_viewport_size(viewsize)
  51. return page
  52. def optimize_page():
  53. # 关闭学习须知
  54. page.evaluate(pop_js)
  55. # 根据当前时间切换夜间模式
  56. hour = time.localtime().tm_hour
  57. if hour >= 18 or hour < 7:
  58. page.wait_for_selector(".Patternbtn-div")
  59. page.evaluate(night_js)
  60. try:
  61. # 关闭上方横幅
  62. page.wait_for_selector(".exploreTip", timeout=500)
  63. page.query_selector('a:has-text("不再提示")').click()
  64. finally:
  65. return
  66. def get_lesson_name():
  67. title_ele = page.wait_for_selector("#lessonOrder")
  68. page.wait_for_timeout(500)
  69. title_ = title_ele.get_attribute("title")
  70. return title_
  71. def move_mouse(elem):
  72. elem.hover()
  73. pos = elem.bounding_box()
  74. # 计算移动的目标位置
  75. target_x = pos['x'] + 30
  76. target_y = pos['y'] + 30
  77. page.mouse.move(target_x, target_y)
  78. def get_progress():
  79. curt = "0%"
  80. canvas = page.wait_for_selector(".videoArea")
  81. move_mouse(canvas)
  82. progress = page.query_selector(".current_play").query_selector(".progress-num")
  83. if not progress:
  84. finish = page.query_selector(".current_play").query_selector(".time_icofinish")
  85. if finish:
  86. curt = "100%"
  87. else:
  88. curt = progress.text_content()
  89. return curt
  90. def check_play():
  91. canvas = page.wait_for_selector(".videoArea")
  92. move_mouse(canvas)
  93. canvas.click()
  94. def video_optimize():
  95. canvas = page.wait_for_selector(".videoArea")
  96. move_mouse(canvas)
  97. page.wait_for_selector(".volumeBox").click() # 设置静音
  98. page.wait_for_selector(".definiBox").hover() # 切换流畅画质
  99. low_quality = page.query_selector(".line1bq")
  100. low_quality.hover()
  101. low_quality.click()
  102. page.wait_for_selector(".speedBox").hover() # 切换1.5倍速
  103. max_speed = page.query_selector(".speedTab15")
  104. max_speed.hover()
  105. max_speed.click()
  106. def play_next():
  107. canvas = page.wait_for_selector(".videoArea")
  108. move_mouse(canvas)
  109. next_but = page.wait_for_selector("#nextBtn")
  110. page.wait_for_timeout(200)
  111. next_but.click()
  112. def skip_question():
  113. try:
  114. page.wait_for_selector(".topic-item", timeout=2000)
  115. choices = page.query_selector_all(".topic-item")
  116. choices[0].click()
  117. choices[1].click()
  118. page.wait_for_timeout(500)
  119. page.query_selector_all(".btn")[3].click()
  120. except TimeoutError:
  121. return
  122. def main_function():
  123. # 进行登录
  124. print("等待登录完成...")
  125. auto_login(user, pwd)
  126. # 等待完成滑块验证,已设置5min等待时间
  127. page.wait_for_selector(".wall-main", state="hidden")
  128. # 遍历所有课程,加载网页
  129. for course_url in urls:
  130. id_pat = re.compile("recruitAndCourseId=[a-zA-Z0-9]+")
  131. matched = re.findall(id_pat, course_url)
  132. if not matched:
  133. print(f"\"{course_url.strip()}\"\n不是一个有效网址,即将自动跳过!")
  134. continue
  135. print("开始加载播放页...")
  136. page.goto(course_url)
  137. page.wait_for_selector(".studytime-div")
  138. # 关闭弹窗,优化页面体验
  139. optimize_page()
  140. # 获取当前课程名
  141. course_title = page.wait_for_selector(".source-name").text_content()
  142. print(f"当前课程:<<{course_title}>>")
  143. start_time = time.time() # 记录开始学习时间
  144. while True:
  145. # 获取课程小节名
  146. title = get_lesson_name()
  147. print("正在学习:%s" % title)
  148. # 根据进度条判断播放状态
  149. curtime = get_progress()
  150. check_play() # 开始播放
  151. video_optimize() # 对播放页进行初始化配置
  152. page.set_default_timeout(2000)
  153. while curtime != "100%":
  154. try:
  155. skip_question() # 跳过中途弹题(只支持选择题)
  156. playBut = page.query_selector_all(".pauseButton")
  157. curtime = get_progress()
  158. if not playBut and curtime != "100%":
  159. check_play()
  160. print("当前小节未刷满,将继续播放..")
  161. title = get_lesson_name()
  162. print("正在学习:%s" % title)
  163. else:
  164. print('完成进度:%s' % curtime)
  165. page.wait_for_timeout(2000)
  166. except TimeoutError:
  167. input("进度获取超时,可能存在安全验证?\n按Enter继续:")
  168. page.set_default_timeout(300 * 1000 * 1000)
  169. title = get_lesson_name()
  170. play_next() # 进度100%时开始下一集
  171. time_period = (time.time() - start_time) / 60
  172. if time_period >= 1: # 每完成一节提示一次时间
  173. print("本次课程已学习:%.1f min" % time_period)
  174. # 如果当前小节是最后一节代表课程学习完毕
  175. all_class = page.query_selector_all(".clearfix.video")
  176. class_name = all_class[-1].get_attribute('class')
  177. if "current_play" in class_name:
  178. print("已学完本课程全部内容!")
  179. print("==" * 10)
  180. break
  181. else: # 否则为完成当前课程的一个小节
  182. print(f"\"{title}\" Done !")
  183. page.wait_for_timeout(1000)
  184. if __name__ == "__main__":
  185. print("===== Runtime Log =====")
  186. try:
  187. print("正在载入数据...")
  188. with open("account.json", "r", encoding="utf-8") as f:
  189. account = json.loads(f.read())
  190. user = account["User"].strip()
  191. pwd = account["Password"].strip()
  192. driver = account["Driver"].strip()
  193. urls = account["Url"]
  194. if not isinstance(urls, list):
  195. print('[Error]"Url"项格式错误!')
  196. raise KeyError
  197. with sync_playwright() as p:
  198. page = init_page()
  199. main_function()
  200. print("==" * 10)
  201. print("所有课程学习完毕!")
  202. input()
  203. except Exception as e:
  204. if isinstance(e, JSONDecodeError):
  205. print("[Error]account文件内容有误!")
  206. elif isinstance(e, KeyError):
  207. print("[Error]可能是account文件的配置出错!")
  208. elif isinstance(e, UserWarning):
  209. print("[Error]是不是忘记填账号密码了?")
  210. elif isinstance(e, FileNotFoundError):
  211. print("[Error]程序缺失依赖文件,请重新安装程序!")
  212. elif isinstance(e, TargetClosedError):
  213. print("[Error]糟糕,网页关闭了!")
  214. elif isinstance(e, TimeoutError):
  215. print("[Error]网页长时间无响应,自动退出...")
  216. else:
  217. print(f"[Error]{e}")
  218. with open("log.txt", "w", encoding="utf-8") as doc:
  219. doc.write(traceback.format_exc())
  220. print("错误日志已保存至:log.txt")
  221. print("系统出错,要不重启一下?")
  222. input()

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/247425
推荐阅读
相关标签
  

闽ICP备14008679号