You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于Selenium WebDriver检测播放列表中第n个HTML5视频结束的通用方案

可靠捕获播放列表中第n个视频结束事件的Selenium方案(适配JW8、VideoJS等HTML5播放器)

我之前处理过不少跨播放器的视频自动化监控需求,结合你描述的播放列表流程——广告→短视频→广告→下一个视频循环,而且所有视频最终都是通过HTML5 <video>元素加载、切换时仅更新src属性的情况,这里给你一套通用的、不需要对接JW8/VideoJS等播放器专属API的方案,完全基于原生HTML5视频事件来实现可靠捕获第n个视频的结束事件:

核心思路

不管上层封装的是哪种播放器,最终的视频渲染都依赖原生的<video>元素,所以我们可以绕开播放器API,直接监听<video>的原生ended事件;同时通过跟踪src属性的变化(或元素替换)来区分不同的视频实例,再配合一个计数机制,就能精准定位到第n个目标视频的结束时刻。

具体实现步骤

  • 第一步:等待页面中的<video>元素加载完成,确保后续能正常绑定事件。
  • 第二步:注入自定义JavaScript脚本到浏览器中,实现三个核心功能:
    • 维护一个视频播放结束的计数器
    • 监听<video>ended事件,每次触发时更新计数器
    • 监听<video>src属性变化(或元素替换),确保事件监听始终绑定在当前活跃的视频元素上
  • 第三步:通过Selenium的显式等待,等待计数器达到目标n值,即第n个视频结束事件触发。

代码示例(Python + Selenium)

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

# 初始化浏览器
driver = webdriver.Chrome()
driver.get("你的播放列表页面URL")

# 等待原生video元素出现
video_element = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.TAG_NAME, "video"))
)

# 注入视频跟踪脚本,传入要监听的第n个视频索引(从1开始计数)
target_video_index = 2  # 这里设置你要捕获的第n个视频
tracker_script = """
window.videoEndCount = 0;
window.isTargetVideoEnded = false;
const targetIndex = arguments[0];

// 绑定ended事件的通用函数
function bindEndEvent(videoEl) {
    // 先移除旧的监听,避免重复触发
    videoEl.removeEventListener('ended', onVideoEnd);
    videoEl.addEventListener('ended', onVideoEnd);
}

// 视频结束时的回调
function onVideoEnd() {
    window.videoEndCount += 1;
    console.log(`第${window.videoEndCount}个视频播放结束`);
    if (window.videoEndCount === targetIndex) {
        window.isTargetVideoEnded = true;
        console.log(`目标视频(第${targetIndex}个)已播放完毕`);
    }
}

// 给初始video绑定事件
bindEndEvent(document.querySelector('video'));

// 监听video元素的src变化或元素替换,确保事件始终有效
const observer = new MutationObserver((mutations) => {
    mutations.forEach((mutation) => {
        // 处理src属性变化的情况
        if (mutation.type === 'attributes' && mutation.attributeName === 'src') {
            bindEndEvent(mutation.target);
        }
        // 处理video元素被替换的情况(部分播放器会这么做)
        if (mutation.type === 'childList') {
            const newVideo = document.querySelector('video');
            if (newVideo) bindEndEvent(newVideo);
        }
    });
});

// 监听video元素本身的属性变化,以及其父元素的子节点变化
observer.observe(document.querySelector('video'), { attributes: true });
observer.observe(document.querySelector('video').parentNode, { childList: true });
"""

# 执行注入脚本,传入目标视频索引
driver.execute_script(tracker_script, target_video_index)

# 等待目标视频结束事件触发,超时时间根据视频最长时长设置(这里设为5分钟)
WebDriverWait(driver, 300).until(
    lambda d: d.execute_script("return window.isTargetVideoEnded;")
)

print(f"第{target_video_index}个视频已成功捕获结束事件!")

# 后续操作:比如继续处理下一个视频、关闭浏览器等
# driver.quit()

进阶优化:区分广告和目标短视频

如果你的需求是仅计数“短视频”而非广告,可以在onVideoEnd回调里添加过滤逻辑,比如通过视频时长或src特征来判断:

function onVideoEnd() {
    // 示例:过滤时长小于30秒的广告视频
    if (this.duration > 30) {
        window.videoEndCount += 1;
        console.log(`第${window.videoEndCount}个目标短视频播放结束`);
        if (window.videoEndCount === targetIndex) {
            window.isTargetVideoEnded = true;
            console.log(`目标短视频(第${targetIndex}个)已播放完毕`);
        }
    } else {
        console.log("广告播放结束,不计数");
    }
}

关键注意事项

  • 超时时间设置:根据你的视频最长时长调整显式等待的超时时间,避免因视频未播放完就触发超时。
  • 元素替换兼容:部分播放器切换视频时会直接替换<video>元素而非仅更新src,所以脚本里同时监听了父元素的子节点变化,确保能重新绑定事件。
  • 跨浏览器支持:这套方案基于HTML5原生API,在Chrome、Firefox、Edge等现代浏览器都能稳定运行。

内容的提问来源于stack exchange,提问作者Nick Slavsky

火山引擎 最新活动