公x课视频播放

公x课视频播放

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

import time

import random

课程ID范围

START_ID = 1406

END_ID = 1449

STAY_TIME = 500 # 每个页面停留时间(秒)

CHECK_INTERVAL = 5 # 检查间隔(秒)

def try_skip_completed_video(driver):

"""尝试快进视频到99%,检测是否已学习完成"""

try:

videos = driver.find_elements(By.TAG_NAME, "video")

复制代码
    if not videos:
        return False  # 没有视频,无法判断
    
    print("尝试快进视频到99%位置...")
    
    for i, video in enumerate(videos):
        try:
            # 首先获取视频时长
            video_info = driver.execute_script("""
                var video = arguments[0];
                if(video.readyState >= 2 && video.duration > 0) {
                    return {
                        duration: video.duration,
                        currentTime: video.currentTime,
                        canSeek: true
                    };
                }
                return null;
            """, video)
            
            if video_info and video_info['duration'] > 0:
                duration = video_info['duration']
                target_time = duration * 0.99  # 99%位置
                
                print(f"视频 {i+1}: 总时长 {duration:.0f}秒,尝试快进到 {target_time:.0f}秒")
                
                # 尝试快进到99%位置
                success = driver.execute_script("""
                    var video = arguments[0];
                    var targetTime = arguments[1];
                    try {
                        video.currentTime = targetTime;
                        return true;
                    } catch(e) {
                        return false;
                    }
                """, video, target_time)
                
                if success:
                    # 等待1秒让视频跳转
                    time.sleep(1)
                    
                    # 检查当前时间是否在99%附近
                    new_info = driver.execute_script("""
                        var video = arguments[0];
                        var targetTime = arguments[1];
                        var current = video.currentTime;
                        var diff = Math.abs(current - targetTime);
                        return {
                            currentTime: current,
                            diff: diff,
                            isClose: diff <= 3  // 允许3秒误差
                        };
                    """, video, target_time)
                    
                    if new_info and new_info['isClose']:
                        print(f"✓ 视频 {i+1} 可快进到99%,当前时间: {new_info['currentTime']:.1f}秒")
                        return True
                    else:
                        print(f"✗ 视频 {i+1} 无法快进到99%,当前时间: {new_info['currentTime']:.1f}秒")
                        return False
                else:
                    print(f"✗ 视频 {i+1} 快进失败,可能无法快进")
                    return False
                    
        except Exception as e:
            print(f"处理视频 {i+1} 时出错: {e}")
            continue
    
    return False
    
except Exception as e:
    print(f"尝试快进视频时出错: {e}")
    return False

def check_if_video_can_be_skipped(driver):

"""检查视频是否可以跳过(已学习完成)"""

先尝试快进检测

if try_skip_completed_video(driver):

return True

复制代码
# 如果快进检测失败,再用传统方法检测完成状态
return check_completion_traditional(driver)

def check_completion_traditional(driver):

"""传统的完成状态检测"""

try:

等待页面加载

time.sleep(3)

复制代码
    # 1. 检查常见的完成状态标识
    completion_indicators = [
        # 文本标识
        ("已完成", "span,div,p,h1,h2,h3,h4,strong"),
        ("100%", "span,div,p"),
        ("已学完", "span,div,p"),
        ("完成学习", "span,div,p"),
        ("学习完成", "span,div,p"),
        ("已完成学习", "span,div,p"),
        ("100%", "span,div,p"),
        # 进度条
        ("progress-bar", "[class*='progress']"),
        ("progress", "[class*='progress']"),
        ("bar", "[class*='bar']"),
    ]
    
    for keyword, selector in completion_indicators:
        try:
            if "%" in keyword or "progress" in keyword or "bar" in keyword:
                # 检查进度条是否显示100%
                elements = driver.find_elements(By.CSS_SELECTOR, selector)
                for element in elements:
                    try:
                        if element.is_displayed():
                            text = element.text.strip()
                            style = element.get_attribute("style") or element.get_attribute("class") or ""
                            
                            # 检查文本中是否包含100%
                            if "100%" in text or "100%" in style:
                                print(f"检测到100%进度: {text[:30]}...")
                                return True
                            
                            # 检查宽度是否为100%
                            if "width: 100%" in style or "width:100%" in style or "width:100%" in style.replace(" ", ""):
                                print("检测到宽度100%的进度条")
                                return True
                    except:
                        continue
            else:
                # 检查文本标识
                elements = driver.find_elements(By.CSS_SELECTOR, f"{selector}")
                for element in elements:
                    try:
                        if element.is_displayed() and keyword in element.text:
                            print(f"检测到完成标识: '{keyword}'")
                            return True
                    except:
                        continue
        except:
            continue
    
    # 2. 检查是否有完成图标
    icon_selectors = [
        "[class*='complete']",
        "[class*='finished']",
        "[class*='success']",
        "[class*='checked']",
        "[class*='icon-success']",
        "[class*='icon-check']",
        "[class*='icon-complete']",
    ]
    
    for selector in icon_selectors:
        try:
            elements = driver.find_elements(By.CSS_SELECTOR, selector)
            for element in elements:
                try:
                    if element.is_displayed():
                        print(f"检测到完成图标: {selector}")
                        return True
                except:
                    continue
        except:
            continue
    
    # 3. 检查按钮状态
    button_texts = ["重新学习", "再次学习", "重新观看", "复习", "已学完", "已完成", "继续学习"]
    
    for text in button_texts:
        try:
            all_buttons = driver.find_elements(By.TAG_NAME, "button")
            for btn in all_buttons:
                try:
                    btn_text = btn.text.strip()
                    if text in btn_text and btn.is_displayed():
                        print(f"检测到按钮文本: '{text}'")
                        return True
                except:
                    continue
        except:
            continue
    
    return False
    
except Exception as e:
    print(f"检查完成状态时出错: {e}")
    return False

def switch_to_window_with_timeout(driver, window_handle, timeout=5):

"""安全切换到指定窗口"""

try:

start_time = time.time()

while time.time() - start_time < timeout:

if window_handle in driver.window_handles:

try:

driver.switch_to.window(window_handle)

return True

except:

time.sleep(0.5)

else:

time.sleep(0.5)

return False

except:

return False

def open_new_tab_safely(driver, url):

"""安全打开新标签页"""

try:

获取当前窗口句柄

current_handle = driver.current_window_handle

复制代码
    # 在新标签页打开
    driver.execute_script(f"window.open('{url}');")
    
    # 等待新窗口打开
    start_time = time.time()
    while time.time() - start_time < 10:  # 最多等待10秒
        if len(driver.window_handles) > 1:
            # 找到新窗口句柄
            new_handles = [h for h in driver.window_handles if h != current_handle]
            if new_handles:
                new_handle = new_handles[-1]
                try:
                    driver.switch_to.window(new_handle)
                    
                    # 等待页面开始加载
                    time.sleep(3)
                    return new_handle, True
                except:
                    pass
        time.sleep(0.5)
    
    return None, False
except Exception as e:
    print(f"打开新标签页失败: {e}")
    return None, False

def handle_quiz_modal(driver, quiz_count):

"""处理答题弹窗"""

try:

查找所有弹窗

modal_selectors = [

".modal",

"[class*='modal']",

"[class*='dialog']",

".el-dialog",

".ant-modal",

"[role='dialog']"

]

复制代码
    for selector in modal_selectors:
        try:
            modals = driver.find_elements(By.CSS_SELECTOR, selector)
            for modal in modals:
                try:
                    if modal.is_displayed():
                        print("检测到答题弹窗,尝试自动答题...")
                        
                        # 查找选项
                        options = modal.find_elements(By.CSS_SELECTOR, 
                                                     "input[type='radio'], "
                                                     "[type='radio'], "
                                                     "[class*='radio'], "
                                                     "[class*='option']")
                        
                        if options and len(options) >= 2:
                            # 先尝试A选项
                            try:
                                options[0].click()
                                print("已选择A选项")
                                time.sleep(1)
                            except:
                                pass
                            
                            # 查找提交按钮
                            buttons = modal.find_elements(By.TAG_NAME, "button")
                            for btn in buttons:
                                try:
                                    if btn.is_displayed() and ("提交" in btn.text or "确定" in btn.text or "确认" in btn.text or "下一步" in btn.text):
                                        btn.click()
                                        quiz_count += 1
                                        print(f"已提交答案(A),第{quiz_count}个答题")
                                        time.sleep(3)
                                        return quiz_count
                                except:
                                    continue
                            
                            # 如果上面没找到,再尝试B选项
                            try:
                                if len(options) >= 2:
                                    options[1].click()
                                    print("已选择B选项")
                                    time.sleep(1)
                                    
                                    for btn in buttons:
                                        try:
                                            if btn.is_displayed() and ("提交" in btn.text or "确定" in btn.text or "确认" in btn.text):
                                                btn.click()
                                                print("已提交答案(B)")
                                                time.sleep(3)
                                                return quiz_count
                                        except:
                                            continue
                            except:
                                pass
                            
                except:
                    continue
                    
        except:
            continue
            
except Exception as e:
    print(f"处理答题弹窗时发生异常: {e}")

return quiz_count

def check_and_handle_quiz(driver, quiz_count):

"""检查并处理答题弹窗"""

try:

检查是否有任何弹窗

modals = driver.find_elements(By.CSS_SELECTOR, "div.modal, div[class*='dialog'], div[role='dialog']")

for modal in modals:

try:

if modal.is_displayed():

modal_text = modal.text[:50]

复制代码
                # 如果是答题相关弹窗
                if any(keyword in modal_text for keyword in ["请选择", "单选题", "多选题", "判断题", "选择", "选项", "答案"]):
                    print("发现可能的答题弹窗")
                    quiz_count = handle_quiz_modal(driver, quiz_count)
                    return quiz_count
                
        except:
            continue
except:
    pass

return quiz_count

def close_current_tab(driver, current_handle):

"""安全关闭当前标签页"""

try:

处理可能的alert弹窗

try:

alert = driver.switch_to.alert

alert.accept()

time.sleep(1)

except:

pass

复制代码
    # 如果有弹窗,尝试点击任何关闭按钮
    try:
        close_buttons = driver.find_elements(By.CSS_SELECTOR, 
                                            "[class*='close'], "
                                            "[aria-label*='关闭'], "
                                            "button.close, "
                                            "[class*='cancel']")
        for btn in close_buttons:
            try:
                if btn.is_displayed() and btn.is_enabled():
                    btn.click()
                    time.sleep(1)
            except:
                continue
    except:
        pass
    
    # 尝试关闭当前窗口
    try:
        if current_handle in driver.window_handles:
            driver.switch_to.window(current_handle)
            driver.close()
            time.sleep(1)
    except:
        pass
    
except Exception as e:
    print(f"关闭标签页时出错: {e}")

def ensure_video_playing(driver):

"""确保视频在播放"""

try:

videos = driver.find_elements(By.TAG_NAME, "video")

复制代码
    if videos:
        for video in videos:
            try:
                is_playing = driver.execute_script("""
                    var video = arguments[0];
                    return !video.paused && video.currentTime > 0;
                """, video)
                
                if not is_playing:
                    driver.execute_script("""
                        var video = arguments[0];
                        if(video.paused && video.readyState >= 2) {
                            video.muted = true;
                            video.play().catch(e => {});
                            return true;
                        }
                        return false;
                    """, video)
            except:
                continue
except:
    pass

def check_video_progress(driver):

"""检查视频播放进度和状态"""

try:

videos = driver.find_elements(By.TAG_NAME, "video")

复制代码
    if not videos:
        return None, 0, False
    
    all_videos_info = []
    
    for i, video in enumerate(videos):
        try:
            video_info = driver.execute_script("""
                var video = arguments[0];
                if(video.readyState >= 2) {
                    return {
                        index: arguments[1],
                        ended: video.ended,
                        currentTime: video.currentTime,
                        duration: video.duration,
                        paused: video.paused,
                        readyState: video.readyState,
                        loop: video.loop
                    };
                }
                return null;
            """, video, i)
            
            if video_info:
                all_videos_info.append(video_info)
        except:
            continue
    
    if not all_videos_info:
        return None, 0, False
    
    # 计算总进度
    total_duration = 0
    total_current_time = 0
    all_ended = True
    
    for info in all_videos_info:
        if info['duration'] > 0:
            total_duration += info['duration']
            total_current_time += info['currentTime']
            if not info['ended']:
                all_ended = False
    
    if total_duration > 0:
        overall_progress = (total_current_time / total_duration) * 100
    else:
        overall_progress = 0
    
    return all_videos_info, overall_progress, all_ended
    
except Exception as e:
    print(f"检查视频进度时出错: {e}")
    return None, 0, False

def check_for_next_section_button(driver):

"""检查是否有下一节/下一章/完成按钮"""

try:

可能的下一节按钮文本

next_button_texts = ["下一节", "下一章", "下一个", "继续", "完成", "下一课", "下一视频", "继续学习", "进入下一节"]

复制代码
    # 查找按钮
    all_buttons = driver.find_elements(By.TAG_NAME, "button")
    for btn in all_buttons:
        try:
            btn_text = btn.text.strip()
            for text in next_button_texts:
                if text in btn_text and btn.is_displayed() and btn.is_enabled():
                    print(f"找到'{text}'按钮,尝试点击...")
                    btn.click()
                    time.sleep(3)
                    return True
        except:
            continue
    
    # 查找链接
    all_links = driver.find_elements(By.TAG_NAME, "a")
    for link in all_links:
        try:
            link_text = link.text.strip()
            for text in next_button_texts:
                if text in link_text and link.is_displayed() and link.is_enabled():
                    print(f"找到'{text}'链接,尝试点击...")
                    link.click()
                    time.sleep(3)
                    return True
        except:
            continue
    
    return False
    
except Exception as e:
    print(f"检查下一节按钮时出错: {e}")
    return False

def smart_video_playback(driver, max_wait_time):

"""智能视频播放管理"""

print(f"监控页面,最大等待 {max_wait_time} 秒...")

start_time = time.time()

quiz_count = 0

last_quiz_check = 0

video_end_count = 0

consecutive_ended = 0

last_progress = 0

stuck_count = 0

has_clicked_next = False

复制代码
while time.time() - start_time < max_wait_time:
    # 检查当前窗口是否仍然有效
    try:
        if driver.window_handles and driver.current_window_handle in driver.window_handles:
            pass
        else:
            print("窗口已关闭,停止监控")
            break
    except:
        print("窗口已关闭,停止监控")
        break
    
    current_time = time.time()
    elapsed = current_time - start_time
    
    # 检查视频进度
    video_info, overall_progress, all_ended = check_video_progress(driver)
    
    if video_info:
        # 检查是否有视频在播放
        has_playing_video = False
        for info in video_info:
            if not info['paused'] and not info['ended']:
                has_playing_video = True
                break
        
        # 如果视频已全部结束
        if all_ended:
            consecutive_ended += 1
            print(f"所有视频已播放完毕 ({consecutive_ended}/2)")
            
            # 如果视频已结束,尝试点击下一节按钮
            if not has_clicked_next:
                print("尝试查找下一节按钮...")
                if check_for_next_section_button(driver):
                    has_clicked_next = True
                    print("已点击下一节按钮,等待页面变化...")
                    time.sleep(5)
                    continue
            
            # 如果连续2次检测到视频已结束,提前退出
            if consecutive_ended >= 2:
                print("视频已播放完毕,且无下一节按钮,提前结束本课程")
                break
        else:
            consecutive_ended = 0
            has_clicked_next = False
            
            # 检查进度是否卡住
            if abs(overall_progress - last_progress) < 0.1 and overall_progress > 0:
                stuck_count += 1
            else:
                stuck_count = 0
            
            last_progress = overall_progress
            
            # 如果进度卡住超过30秒
            if stuck_count >= 6:  # 6 * 5秒 = 30秒
                print("检测到视频进度卡住,尝试重新播放...")
                try:
                    # 重新播放视频
                    driver.execute_script("""
                        var videos = document.querySelectorAll('video');
                        for(var v of videos) {
                            if(v.paused && v.readyState >= 2) {
                                v.muted = true;
                                v.play().catch(e => {});
                            }
                        }
                    """)
                    stuck_count = 0
                    time.sleep(3)
                except:
                    pass
        
        # 显示进度信息
        if overall_progress > 0 and overall_progress < 100:
            print(f"总进度: {overall_progress:.1f}%", end="\r")
    
    # 每8秒检查一次答题弹窗
    if current_time - last_quiz_check > 8:
        quiz_count = check_and_handle_quiz(driver, quiz_count)
        last_quiz_check = current_time
    
    # 每10秒确保视频在播放
    if int(elapsed) % 10 == 0:
        ensure_video_playing(driver)
    
    # 显示剩余时间
    remaining = int(max_wait_time - elapsed)
    if remaining > 0:
        mins, secs = divmod(remaining, 60)
        elapsed_mins, elapsed_secs = divmod(int(elapsed), 60)
        print(f"已学: {elapsed_mins:02d}:{elapsed_secs:02d} | 剩余: {mins:02d}:{secs:02d} | 答题: {quiz_count} | 进度: {overall_progress:.1f}%", end="\r")
    
    time.sleep(CHECK_INTERVAL)

actual_time = int(time.time() - start_time)
return quiz_count, actual_time

def main():

"""主函数"""

print("公需课学习助手")

print(f"课程范围: {START_ID} - {END_ID}")

print(f"每个课程停留: {STAY_TIME} 秒")

print("=" * 50)

复制代码
# 初始化浏览器
options = webdriver.EdgeOptions()
options.add_argument("--disable-notifications")
options.add_argument("--disable-popup-blocking")

driver = webdriver.Edge(options=options)

# 设置页面加载超时
driver.set_page_load_timeout(30)
driver.set_script_timeout(30)

try:
    # 打开第一个页面并登录
    first_url = f"https://www.gdysxh.com/my_classes/public_course/video/course_id/{START_ID}/order_id/277288.html"
    print("打开第一个课程,请手动登录...")
    driver.get(first_url)
    
    input("登录完成后按回车键继续...")
    
    # 保存主窗口句柄
    main_window = driver.current_window_handle
    
    # 遍历所有课程
    for course_id in range(START_ID, END_ID + 1):
        url = f"https://www.gdysxh.com/my_classes/public_course/video/course_id/{course_id}/order_id/277288.html"
        
        print(f"\n{'='*50}")
        print(f"正在处理课程 {course_id}...")
        print(f"URL: {url}")
        
        # 安全打开新标签页
        new_handle, success = open_new_tab_safely(driver, url)
        
        if not success or not new_handle:
            print(f"⚠ 无法打开课程 {course_id} 的页面,跳过")
            continue
        
        # 检查窗口是否有效
        if not switch_to_window_with_timeout(driver, new_handle):
            print(f"⚠ 无法切换到课程 {course_id} 的窗口,跳过")
            continue
        
        # 等待页面加载
        time.sleep(3)
        
        # 检查课程是否已完成(先尝试快进检测)
        print("检查课程完成状态...")
        try:
            if check_if_video_can_be_skipped(driver):
                print(f"✓ 课程 {course_id} 已完成(可快进),跳过")
                
                # 关闭当前标签页
                close_current_tab(driver, new_handle)
                
                # 切换回主窗口
                if not switch_to_window_with_timeout(driver, main_window):
                    # 如果主窗口不存在,使用第一个窗口
                    if driver.window_handles:
                        driver.switch_to.window(driver.window_handles[0])
                        main_window = driver.current_window_handle
                
                continue
        except Exception as e:
            print(f"检查完成状态时出错: {e}")
            # 继续尝试学习
        
        print("课程未完成,开始学习...")
        
        # 关闭初始弹窗
        try:
            close_buttons = driver.find_elements(By.CSS_SELECTOR, 
                                                "[class*='close'], "
                                                "[aria-label*='关闭'], "
                                                "button.close")
            for btn in close_buttons:
                try:
                    if btn.is_displayed():
                        btn.click()
                        time.sleep(1)
                except:
                    continue
        except:
            pass
        
        # 尝试播放视频
        print("尝试播放视频...")
        try:
            driver.execute_script("""
                var videos = document.querySelectorAll('video');
                for(var v of videos) {
                    if(v.paused && v.readyState >= 2) {
                        v.muted = true;
                        v.play().catch(e => {});
                    }
                }
            """)
            time.sleep(3)
        except Exception as e:
            print(f"播放视频失败: {e}")
            # 继续监控页面
        
        # 智能监控视频播放
        quiz_count, actual_time = smart_video_playback(driver, STAY_TIME)
        
        mins, secs = divmod(actual_time, 60)
        print(f"\n✓ 课程 {course_id} 处理完成,用时 {mins:02d}:{secs:02d},共处理 {quiz_count} 个答题")
        
        # 关闭当前标签页
        print("关闭当前标签页...")
        close_current_tab(driver, new_handle)
        
        # 切换回主窗口
        if not switch_to_window_with_timeout(driver, main_window):
            # 如果主窗口不存在,使用第一个窗口
            if driver.window_handles:
                driver.switch_to.window(driver.window_handles[0])
                main_window = driver.current_window_handle
        
        # 短暂等待
        if course_id < END_ID:
            time.sleep(2)
    
    print("\n" + "="*50)
    print(f"所有课程处理完成!共 {END_ID - START_ID + 1} 个课程")
    print("="*50)
    
except Exception as e:
    print(f"\n程序出错: {e}")
    import traceback
    traceback.print_exc()

# 保持浏览器打开
input("按回车键关闭浏览器...")
try:
    driver.quit()
except:
    pass

if name == "main ":

main()

相关推荐
郝学胜-神的一滴4 分钟前
线程同步:并行世界的秩序守护者
java·linux·开发语言·c++·程序人生
龘龍龙5 分钟前
Python基础学习(十)
服务器·python·学习
superman超哥5 分钟前
Rust 移动语义(Move Semantics)的工作原理:零成本所有权转移的深度解析
开发语言·后端·rust·工作原理·深度解析·rust移动语义·move semantics
青茶3606 分钟前
【js教程】如何用jq的js方法获取url链接上的参数值?
开发语言·前端·javascript
轻竹办公PPT7 分钟前
用 AI 制作 2026 年工作计划 PPT,需要准备什么
大数据·人工智能·python·powerpoint
Mqh1807628 分钟前
day58 经典时序预测模型
python
Amelia1111118 分钟前
day44
python
高洁0112 分钟前
10分钟了解向量数据库(1)
python·深度学习·机器学习·transformer·知识图谱
DP+GISer13 分钟前
00基于pytorch的深度学习遥感地物分类全流程实战教程(包含遥感深度学习数据集制作与大图预测)-前言
pytorch·python·深度学习·图像分割·遥感·地物分类
superman超哥16 分钟前
Rust 所有权转移在函数调用中的表现:编译期保证的零成本抽象
开发语言·后端·rust·函数调用·零成本抽象·rust所有权转移