自动刷课程序DEMO V1 基于慕课
程序内容
- 程序概述
前置操作:脚本使用前置环境
此程序主要是通过 Selenium 自动化浏览器,模拟登录并观看在线视频的过程。包括了一些自动化操作,比如获取视频信息、控制视频播放、暂停以及跳转到下一个视频等
目前程序在B站,A站和mooc网测试使用,在mooc网使用时需要调用登录函数,其他两个不用
- 程序目标
自动登录到一个视频网站(例如慕课网或B站),然后模拟观看视频。通过获取视频的状态,监控视频的播放、暂停、进度等信息,并在视频结束后自动切换到下一个视频。
- 程序结构与主要功能
- 配置登录信息:
指定登录页面的URL和目标课程的视频页面URL。需要登陆的页面可以需要输入用户名(username)和密码(password),但目前仅适配mooc网。 - 浏览器配置 (setup_browser):
使用 Selenium WebDriver(Chrome)设置浏览器选项,并打开指定的课程视频页面。还可以配置为无头模式(即不显示浏览器界面)。 - 登录功能 (login_with_selenium):
使用 Selenium 自动填写用户名和密码,提交登录表单。此部分功能目前被注释掉,仅作为mooc网功能使用。 - 视频播放监控与模拟观看 (simulate_video_watch):
这个函数不断监控当前视频的状态(播放、暂停、播放进度等),并且在视频结束后,自动跳转到下一个视频,直到播放所有视频或出现异常。 - 视频信息获取 (get_video_info):
使用 JavaScript 通过 Selenium 获取视频元素的时长、当前播放时间、暂停状态、结束状态和视频地址。此信息用于判断视频的播放进度。 - 按钮查找功能 (seach_video_button):
通过 XPath 查找播放、暂停、下一个视频等按钮。程序根据页面中的不同元素进行匹配。这个函数有两个主要类型的按钮:播放按钮和下一个按钮。 - 按钮确认与点击功能:
confirm_play_button: 确认视频播放按钮并点击,确保视频能正常播放。
confirm_next_button: 确认下一个按钮并点击,切换到下一个视频。 - 自动播放检测 (is_auto_play_next):
通过检测视频是否发生变化来判断是否启用了自动播放功能。自动播放检测帮助程序确认是否继续进行下一个视频的播放。 - 按钮点击 (click_button):
通过执行 JavaScript,模拟点击指定的按钮(例如播放、暂停或跳过按钮)。
- 程序流程
- 初始化和浏览器设置:
程序首先设置 Selenium 的浏览器并打开目标视频页面。 - 登录操作:
如果需要,程序会自动登录指定的网站账号。 - 确认播放按钮:
程序尝试通过查找页面上的播放按钮,确认视频是否已准备好播放,并点击播放按钮(如果未播放)。 - 模拟观看视频:
- 程序获取视频的状态(例如当前播放时间、是否暂停等),并每隔10秒检查一次视频的状态。
- 如果视频暂停,则自动恢复播放。
- 如果视频播放完毕,则继续查找下一个视频并进行播放。
- 自动跳转到下一个视频:
程序检测视频是否结束,并在结束后自动点击“下一个”按钮,跳转到下一个视频。 - 统计数据:
程序统计已观看视频的数量和总时长,并输出到控制台。
- 后续改进计划 To Be Continue
- 2025.1.15
- 错误处理:完善错误处理,增强鲁棒性,调整参数如页面加载时间的延迟等。
- 提高自动化:登录部分有注释仅适用于mooc网,且浏览器默认是可视化的(显示界面),后续完善测试无头模式和自动登录可行性,提高效率,避免干扰。
- 并发支持:目前程序是单线程的,适用于逐个视频播放。如果需要,可以通过多线程或并发来提高效率,自动化播放多个视频。
- 平台支持
- 慕课网IMOOC
- Bilibili
- Acfun
- 更新日志
- 2025.1.15 更新初版功能 V1.0
- 2025.1.20 V1.0.1:修复bug:部分网站拦截javascript执行点击按钮的操作,还原回Selenium的模拟点击操作
程序代码
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
import time
# 配置登录信息
username = "xxxx" # 替换为实际的用户名
password = "xxxx" # 替换为实际的密码
login_url = "https://www.imooc.com/login" # 登录页面 URL
course_url = "https://www.bilibili.com/video/BV1sJcJeREHv/?spm_id_from=333.1007.tianma.1-1-1.click" # 课程视频页面 URL
# 是否启用 requests.Session 优化(True 使用 Session,False 使用正常 Selenium 登录)
#USE_SESSION = True
#统计数据
VIDEO_COUNT = 0
VIDEO_TIME = 0
VIDEO_SRC = None
#按钮/发现存在页面不同,元素不同的可能性,因此只有每次使用再去遍历
BUTTON_PLAY = None #播放按钮
BUTTON_PAUSE = None #暂停按钮
BUTTON_NEXT = None #下一个按钮
auto_play_next = None #自动播放下一个视频检测
# 使用 Selenium 执行正常的浏览器登录
def login_with_selenium(driver):
# 找到用户名、密码输入框并输入相应的账号和密码
username_input = driver.find_element(By.NAME, "email") # 假设用户名字段的 name 为 'email'
password_input = driver.find_element(By.NAME, "password") # 假设密码字段的 name 为 'password'
# 输入用户名和密码
username_input.send_keys(username)
password_input.send_keys(password)
# 提交表单(按 Enter 键)
password_input.send_keys(Keys.RETURN)
# 等待页面加载,直到课程视频页面加载完成
time.sleep(5)
return driver
# 设置 Selenium 浏览器
def setup_browser():
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
# options.add_argument('--headless') # 无头模式(可选,不显示浏览器界面)
options.add_argument("--start-maximized")
options.add_argument('--disable-gpu') # 禁用GPU加速(可选)
options.add_argument("--no-sandbox")
options.add_argument("user-agent=xxxx") 查找并输入自己的浏览器代理
driver = webdriver.Chrome(options=options)
# 打开登录页面
driver.get(course_url)
time.sleep(2) # 等待页面加载
print(f"等待完毕")
return driver
# 模拟观看视频
def simulate_video_watch(driver):
video_info = get_video_info(driver)
global VIDEO_COUNT,VIDEO_TIME,VIDEO_SRC
if video_info is not None:
if VIDEO_SRC != video_info['src']:
VIDEO_SRC = video_info['src']
VIDEO_COUNT += 1
VIDEO_TIME += video_info['duration']
print(f"播放视频{VIDEO_COUNT},视频时长:{video_info['duration']} 秒")
while not video_info['ended'] and VIDEO_SRC == video_info['src']:
if video_info['paused']:
print(f"WARNING:检测到视频暂停")
#click_play_button(driver)
click_button(driver,BUTTON_PLAY)
if video_info['duration'] > 0:
VIDEO_PROGRESS = round((video_info['currentTime'] / video_info['duration']) * 100, 2)
else:
VIDEO_PROGRESS = 0
print(f"check:")
print(f" 当前播放时间:{round(video_info['currentTime'], 2)}秒")
print(f" 当前视频进度:{VIDEO_PROGRESS}%")
time.sleep(10) # 模拟观看视频,每10s检查视频状态
video_info = get_video_info(driver)
print(f"播放完毕")
print(f"********************************")
time.sleep(2)
if not is_auto_play_next(driver):
if not confirm_next_button(driver):
print("无可进行操作,无法进行下一步")
return
time.sleep(5)
simulate_video_watch(driver)
else:
while VIDEO_SRC == video_info['src']:
print("等待2s")
time.sleep(2)
video_info = get_video_info(driver)
simulate_video_watch(driver)
#获取视频元素的信息
def get_video_info(driver):
try:
# 执行 JavaScript 获取视频元素的时长
video_info = driver.execute_script("""
var video = document.querySelector('video'); // 获取页面中的第一个 <video> 标签
if (video) {
return {
duration: video.duration, // 视频时长(单位:秒)
currentTime: video.currentTime, // 当前播放时间(单位:秒)
paused: video.paused, // 是否暂停
ended: video.ended, // 是否播放完毕
src: video.src //视频地址
};
} else {
return null; // 如果没有找到视频元素,返回 null
}
""")
if video_info:
return video_info
else:
print("未能找到视频元素")
return None
except Exception as e:
print(f"获取视频信息失败:{e}")
return None
#查找播放按钮
def seach_video_button(driver, Type):
print(f"查找")
try:
# 查找按钮
if Type == 'play':
play_buttons = WebDriverWait(driver, 10).until(
EC.presence_of_all_elements_located(
(By.XPATH,
"//button[contains(translate(text(), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'PLAY')] | "
"//button[contains(translate(@aria-label, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'PLAY')] | "
"//button[contains(translate(@data-action, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'PLAY')] | "
"//button[contains(translate(@class, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'PLAY')] | "
"//i[contains(translate(@class, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'PLAY')] | "
"//div[contains(translate(@class, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'PLAY')] | "
"//span[contains(translate(@class, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'PLAY')]"
)
)
)
if Type == 'next':
play_buttons = WebDriverWait(driver, 10).until(
EC.presence_of_all_elements_located(
(By.XPATH,
"//button[contains(translate(text(), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'NEXT')] | "
"//button[contains(translate(@aria-label, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'NEXT')] | "
"//button[contains(translate(@data-action, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'NEXT')] | "
"//button[contains(translate(@class, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'NEXT')] | "
"//i[contains(translate(@class, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'NEXT')] | "
"//div[contains(translate(@class, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'NEXT')] | "
"//span[contains(translate(@class, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'NEXT')]"
)
)
)
if not play_buttons:
print("没有找到符合条件的按钮")
return False
else:
# 输出所有找到的按钮
print(f"共找到 {len(play_buttons)} 个按钮")
return play_buttons
except Exception as e:
print(f"无法找到按钮")
return False
#确认真正的播放按钮
def confirm_play_button(driver):
buttons = seach_video_button(driver, 'play')
if not buttons:
return
video_info = get_video_info(driver)
if video_info['ended'] or video_info is None:
return
global BUTTON_PLAY,BUTTON_PAUSE
VIDEO_STATUS = video_info['paused']
index = 0
while index < len(buttons):
button = buttons[index]
if BUTTON_PAUSE is not None and BUTTON_PLAY is not None:
break
click_button(driver,button)
video_info = get_video_info(driver)
if VIDEO_STATUS != video_info['paused']:
print(f"找到有效按钮!")
time.sleep(2)
VIDEO_STATUS = video_info['paused']
if video_info['paused']:
BUTTON_PAUSE = button
print(f"已找到暂停按钮")
else:
BUTTON_PLAY = button
print(f"已找到播放按钮")
else:
index += 1
time.sleep(1)
print(f"检索完毕")
#确认真正的下一个按钮
def confirm_next_button(driver):
global BUTTON_NEXT
if BUTTON_NEXT is not None:
click_button(driver,BUTTON_NEXT)
time.sleep(1)
video_info = get_video_info(driver)
if VIDEO_SRC == video_info['src']:
print(f"原下一步按钮失效,尝试重新获取")
else:
return True
buttons = seach_video_button(driver, 'next')
if not buttons:
print(f"无有效button")
return False
video_info = get_video_info(driver)
if video_info is None:
print(f"无视频信息")
return False
for button in buttons:
click_button(driver,button)
time.sleep(1)
video_info = get_video_info(driver)
if VIDEO_SRC != video_info['src']:
print(f"找到有效按钮!")
BUTTON_NEXT = button
return True
print(f"检索完毕")
return False
#查找是否自动播放
def is_auto_play_next(driver):
global auto_play_next
if auto_play_next is None:
time.sleep(15)
video_info = get_video_info(driver)
if VIDEO_SRC != video_info['src']:
print(f"检测到自动播放!")
auto_play_next = True
else:
print(f"未检测到自动播放!")
auto_play_next = False
return auto_play_next
#点击按钮
def click_button(driver,button):
try:
#driver.execute_script("arguments[0].click();", button)
button.click()
except Exception as e:
print("error:无法点击按钮")
# 主程序
def main():
driver = setup_browser()
# 登录
#login_with_selenium(driver)
confirm_play_button(driver)
if BUTTON_PLAY is not None and BUTTON_PAUSE is not None:
simulate_video_watch(driver)
# 完成操作后退出
print(f"===============================")
print(f"播放结束,共计播放视频个数:{VIDEO_COUNT} 总视频时间:{VIDEO_TIME} 秒")
#driver.quit()
# 执行主程序
if __name__ == "__main__":
main()
一条评论
Pingback: