You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Selenium自动化YouTube频道滚动加载视频失效问题

YouTube频道视频爬取:滚动加载停滞问题排查与解决

根因分析

  • 固定等待时间不足:代码中Thread.sleep(1000)是固定等待,YouTube加载视频的时间受网络、页面渲染速度影响,若1秒内未完成新视频加载,会误判为已到达页面底部,停止滚动。
  • 滚动容器定位错误:使用document.documentElement.scrollHeight获取整个文档的高度,但YouTube的视频列表实际在独立的滚动容器内,整个文档的高度变化不能准确反映视频列表的加载状态。
  • 滚动逻辑存在漏洞:window.scrollTo(0, startHeight)是滚动到当前文档的高度,若此时页面还在加载中,滚动高度未更新,会重复滚动到同一位置,无法触发新视频加载。
  • 反爬机制限制:频繁的JavaScript滚动操作可能被YouTube的反爬机制识别,停止返回新的视频内容。

可行的替代解决方案

方案1:针对视频列表容器滚动+动态等待

直接定位到YouTube视频列表的滚动容器,滚动该容器并等待新视频元素加载,避免依赖整个文档的高度变化:

WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
driver.get("https://www.youtube.com/@LambdaTest/videos");
JSONArray resultArray = new JSONArray();

// 处理Cookie弹窗
try {
    wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//button[@aria-label='Accept all']"))).click();
} catch (Exception e) {}

driver.manage().window().maximize();
JavascriptExecutor js = (JavascriptExecutor) driver;

// 定位视频列表的滚动容器
WebElement scrollContainer = driver.findElement(By.cssSelector("ytd-rich-grid-renderer #contents"));
int previousVideoCount = 0;

do {
    previousVideoCount = driver.findElements(By.cssSelector("ytd-rich-item-renderer #content")).size();
    // 滚动到容器底部
    js.executeScript("arguments[0].scrollTop = arguments[0].scrollHeight", scrollContainer);
    // 等待新视频加载,最多等待5秒,直到视频数量增加
    try {
        wait.until(d -> driver.findElements(By.cssSelector("ytd-rich-item-renderer #content")).size() > previousVideoCount);
    } catch (TimeoutException e) {
        // 超时说明没有新视频加载,退出循环
        break;
    }
} while (true);

// 爬取视频数据
List<WebElement> allVideos = driver.findElements(By.cssSelector("ytd-rich-item-renderer #content"));
for (WebElement video : allVideos) {
    WebElement title = video.findElement(By.cssSelector("#video-title-link"));
    List<WebElement> metaData = video.findElements(By.cssSelector("#metadata-line span"));
    
    JSONObject videoData = new JSONObject();
    videoData.put("video_title", title.getText());
    videoData.put("video_views", metaData.get(0).getText());
    videoData.put("video_days", metaData.get(1).getText());
    
    resultArray.add(videoData);
}

System.out.println(resultArray);
driver.quit();

方案2:模拟用户键盘滚动(PageDown)

用模拟键盘按下PageDown的方式代替JavaScript滚动,更贴近真实用户操作,降低被反爬识别的概率:

// 省略初始化、Cookie处理等重复代码
Actions actions = new Actions(driver);
int previousCount = 0;
int currentCount;

do {
    previousCount = driver.findElements(By.cssSelector("ytd-rich-item-renderer #content")).size();
    // 连续按下PageDown键模拟滚动
    for (int i = 0; i < 6; i++) {
        actions.sendKeys(Keys.PAGE_DOWN).perform();
        Thread.sleep(400); // 短等待让页面响应
    }
    currentCount = driver.findElements(By.cssSelector("ytd-rich-item-renderer #content")).size();
} while (currentCount > previousCount);

// 后续爬取代码同方案1

方案3:优化原滚动逻辑,替换固定等待为显式等待

保留原JavaScript滚动的思路,但用显式等待替代固定Thread.sleep,确保等待到页面加载完成:

// 省略初始化、Cookie处理等重复代码
JavascriptExecutor js = (JavascriptExecutor) driver;
long lastScrollHeight = 0;
boolean hasNewContent;

do {
    lastScrollHeight = (long) js.executeScript("return document.documentElement.scrollHeight");
    js.executeScript("window.scrollTo(0, document.documentElement.scrollHeight)");
    
    // 等待3秒,检查滚动高度是否变化
    hasNewContent = new WebDriverWait(driver, Duration.ofSeconds(3)).until(d -> {
        long currentScrollHeight = (long) js.executeScript("return document.documentElement.scrollHeight");
        return currentScrollHeight > lastScrollHeight;
    });
} while (hasNewContent);

// 后续爬取代码同方案1

额外注意事项

  • 反爬应对:避免过于频繁的操作,适当调整等待时间;可以通过driver.executeScript("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")隐藏Selenium的webdriver标识。
  • 元素定位优化:优先使用CSS选择器(如ytd-rich-item-renderer #content),比XPath更稳定,不易因页面结构小变化失效。

内容的提问来源于stack exchange,提问作者Sohail M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 14:14:55