Skip to content

Commit e63e756

Browse files
committed
v3.0 无需每次扫码重复登录、切出窗口时视频播放不暂停、自动完成某个课程的所有视频、支持无窗口模式后台播放
1 parent 8c9ebb9 commit e63e756

File tree

1 file changed

+125
-103
lines changed

1 file changed

+125
-103
lines changed

main.py

Lines changed: 125 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,131 @@
11
'''
22
Author: LetMeFly
3-
Date: 2021-11-01 15:52:32
3+
Date: 2023-09-12 20:49:21
44
LastEditors: LetMeFly
5-
LastEditTime: 2023-09-12 19:27:08
5+
LastEditTime: 2023-09-22 21:38:54
6+
Description: 开源于https://github.com/LetMeFly666/YuketangAutoPlayer 欢迎issue、PR
67
'''
7-
88
from selenium import webdriver
9+
from selenium.webdriver import ActionChains
10+
from selenium.webdriver.support.ui import WebDriverWait
911
from time import sleep
10-
driver = webdriver.Chrome()
11-
12-
# 访问雨课堂并点击“登录”按钮
13-
driver.get("https://grsbupt.yuketang.cn/")
14-
driver.find_element_by_class_name("login-btn").click()
15-
print("请扫码登陆")
16-
17-
# 判断是否已经登陆成功
18-
while True:
19-
location = driver.current_url
20-
if "courselist" in location:
21-
break
22-
sleep(0.5)
23-
print("登录成功")
24-
25-
# 完成一门课程的函数
26-
def finishThisCourse(courseId):
27-
# 访问此视频
28-
driver.get("https://grsbupt.yuketang.cn/pro/lms/84eubUXLHEy/17556639/video/" + courseId)
29-
# 判断是否已经完成
30-
sleep(3)
31-
if len(driver.find_elements_by_class_name("icon--gou")):
32-
print("此课程已完成")
33-
return True
34-
def ifCouldPlayAVideo():
35-
videoTag = driver.find_element_by_id("video-box")
36-
return len(videoTag.find_elements_by_tag_name("div"))
37-
couldPlayVideo = False
38-
for tryTimes in range(5): # 尝试5次,一次可能是因为网络,5次大概率不是视频
39-
if ifCouldPlayAVideo():
40-
couldPlayVideo = True
41-
print("是课程")
42-
break
43-
sleep(2)
44-
if not couldPlayVideo:
45-
print("不是课程")
46-
return False # 认为不是视频
47-
sleep(5)
48-
# video = driver.find_element_by_tag_name("video")
49-
# def ifVideoPaused():
50-
# result = driver.execute_script("return document.querySelector('video').paused;")
51-
# return result
52-
# tryToPlayTimes = 0
53-
# while ifVideoPaused():
54-
# print("暂停状态")
55-
# try:
56-
# playButton = driver.find_element_by_class_name('xt_video_player_play_btn')
57-
# playButton.click()
58-
# except:
59-
# driver.execute_script("document.querySelector('.xt_video_player_play_btn').click();")
60-
# driver.execute_script("console.log(document.querySelector('.xt_video_player_play_btn'));")
61-
# driver.execute_script("document.querySelector('video').play();")
62-
# tryToPlayTimes += 1
63-
# if tryToPlayTimes > 7:
64-
# driver.refresh()
65-
# tryToPlayTimes = 0
66-
# # while True:
67-
# # try:
68-
# # script = input("请输入要执行的脚本")
69-
# # print(driver.execute_script(script))
70-
# # except:
71-
# # print("执行失败")
72-
# sleep(3)
73-
# sleep(1)
74-
75-
driver.execute_script("video = document.querySelector('video');")
76-
element_video = driver.find_element_by_tag_name('video')
77-
webdriver.ActionChains(driver).move_to_element(element_video).perform()
78-
webdriver.ActionChains(driver).click().perform()
79-
driver.execute_script("startVideo = setInterval(() => {video.play(); console.log('尝试播放视频');}, 1000); setTimeout(() => {clearInterval(startVideo); console.log('停止尝试播放视频')}, 5200);")
80-
print("正在播放")
81-
driver.execute_script("video.addEventListener('pause', function() {video.play();});")
82-
sleep(5)
83-
element_speeds = driver.find_element_by_class_name('xt_video_player_common_value')
84-
webdriver.ActionChains(driver).move_to_element(element_speeds).perform()
85-
sleep(0.2)
86-
element_speed2 = driver.find_element_by_xpath('//*[@id="video-box"]/div/xt-wrap/xt-controls/xt-inner/xt-speedbutton/xt-speedlist/ul/li[1]')
87-
webdriver.ActionChains(driver).move_to_element_with_offset(element_speed2, 3, 5).perform()
88-
sleep(0.3)
89-
element_speed2.click()
90-
# webdriver.ActionChains(driver).context_click(element_speed2).perform()
91-
92-
while not len(driver.find_elements_by_class_name("icon--gou")):
93-
sleep(1)
94-
print("此课程播放完毕!")
95-
return True
96-
97-
98-
# 访问每一门课
99-
for courseId in range(37551787, 37551907 + 1):
100-
# try:
101-
if True:
102-
finishThisCourse(str(courseId))
103-
# except:
104-
# pass
105-
print("全部完成!")
106-
107-
108-
109-
# 雨课堂字幕:https://buct.yuketang.cn/mooc-api/v1/lms/service/subtitle_parse/?c_d=0D0C4F3DE7D58B649C33DC5901307461&lg=0&_=1665473764724
12+
import random
13+
14+
15+
IF_HEADLESS = False # 是否以无窗口模式运行(首次运行建议使用有窗口模式以观察是否符合预期)
16+
COURSE_URL = 'https://grsbupt.yuketang.cn/pro/lms/84eubUXLHEy/17556639/studycontent' # 要刷的课的地址(获取方式见README)
17+
COOKIE = 'sjfeij2983uyfh84y7498uf98ys8f8u9' # 打死也不要告诉别人哦(获取方式见README)
18+
19+
20+
option = webdriver.ChromeOptions()
21+
22+
if IF_HEADLESS:
23+
option.add_argument('--headless')
24+
25+
driver = webdriver.Chrome(options=option)
26+
driver.maximize_window()
27+
driver.implicitly_wait(20)
28+
29+
def str2dic(s):
30+
d = dict()
31+
for i in s.split('; '):
32+
temp = i.split('=')
33+
d[temp[0]] = temp[1]
34+
return d
35+
36+
37+
def setCookie(cookies):
38+
driver.delete_all_cookies()
39+
for name, value in cookies.items():
40+
driver.add_cookie({'name': name, 'value': value, 'path': '/'})
41+
42+
43+
def ifVideo(div):
44+
i = div.find_element_by_tag_name('i')
45+
i_class = i.get_attribute('class')
46+
return 'icon--shipin' in i_class
47+
48+
49+
def getAllvideos_notFinished(allClasses):
50+
allVideos = []
51+
for thisClass in allClasses:
52+
if ifVideo(thisClass) and '已完成' not in thisClass.text:
53+
allVideos.append(thisClass)
54+
return allVideos
55+
56+
57+
def get1video_notFinished(allClasses):
58+
for thisClass in allClasses:
59+
if ifVideo(thisClass) and '已完成' not in thisClass.text:
60+
return thisClass
61+
return None
62+
63+
64+
# driver.get('https://grsbupt.yuketang.cn/')
65+
driver.get('https://' + COURSE_URL.split('https://')[1].split('/')[0] + '/')
66+
cookies = {'sessionid': COOKIE}
67+
setCookie(cookies)
68+
driver.get(COURSE_URL)
69+
70+
71+
def change2speed2():
72+
speedbutton = driver.find_element_by_tag_name('xt-speedbutton')
73+
ActionChains(driver).move_to_element(speedbutton).perform()
74+
ul = speedbutton.find_element_by_tag_name('ul')
75+
lis = ul.find_elements_by_tag_name('li')
76+
li_speed2 = lis[0]
77+
diffY = speedbutton.location['y'] - li_speed2.location['y']
78+
# ActionChains(driver).move_to_element_with_offset(speedbutton, 3, 5).perform()
79+
# ActionChains(driver).click().perform()
80+
# 我也不知道为啥要一点一点移动上去,反正直接移动上去的话,点击是无效的
81+
for i in range(diffY // 10): # 可能不是一个好算法
82+
ActionChains(driver).move_by_offset(0, -10).perform()
83+
sleep(0.5)
84+
sleep(0.8)
85+
ActionChains(driver).click().perform()
86+
87+
88+
def mute1video():
89+
if driver.execute_script('return video.muted;'):
90+
return
91+
voice = driver.find_element_by_tag_name('xt-volumebutton')
92+
ActionChains(driver).move_to_element(voice).perform()
93+
ActionChains(driver).click().perform()
94+
95+
96+
def finish1video():
97+
allClasses = driver.find_elements_by_class_name('leaf-detail')
98+
allVideos = getAllvideos_notFinished(allClasses)
99+
if not allVideos:
100+
return False
101+
video = allVideos[0]
102+
driver.execute_script('arguments[0].scrollIntoView(false);', video)
103+
video.click()
104+
105+
driver.switch_to.window(driver.window_handles[-1])
106+
WebDriverWait(driver, 10).until(lambda x: driver.execute_script('video = document.querySelector("video"); console.log(video); return video;')) # 这里即使2次sleep3s选中的video还是null
107+
driver.execute_script('videoPlay = setInterval(function() {if (video.paused) {video.play();}}, 200);')
108+
driver.execute_script('setTimeout(() => clearInterval(videoPlay), 5000)')
109+
driver.execute_script('addFinishMark = function() {finished = document.createElement("span"); finished.setAttribute("id", "LetMeFly_Finished"); document.body.appendChild(finished); console.log("Finished");}')
110+
driver.execute_script('lastDuration = 0; setInterval(() => {nowDuration = video.currentTime; if (nowDuration < lastDuration) {addFinishMark()}; lastDuration = nowDuration}, 200)')
111+
driver.execute_script('video.addEventListener("pause", () => {video.play()})')
112+
mute1video()
113+
change2speed2()
114+
while True:
115+
if driver.execute_script('return document.querySelector("#LetMeFly_Finished");'):
116+
print('finished, wait 5s')
117+
sleep(5) # 再让它播5秒
118+
driver.close()
119+
driver.switch_to.window(driver.window_handles[-1])
120+
return True
121+
else:
122+
print(f'not finished {random.random()}')
123+
sleep(3)
124+
return False
125+
126+
127+
while finish1video():
128+
driver.refresh()
129+
driver.quit()
130+
print('恭喜你!全部播放完毕')
131+
sleep(5)

0 commit comments

Comments
 (0)