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

如何用Crawlee/Apify抓取带无限滚动的Twitch页面?

解决Twitch VTuber频道无限滚动抓取问题

你的问题出在infiniteScroll的默认配置不匹配Twitch主页面的滚动结构,导致滚动逻辑没在主页面生效,反而被带到了详情页。以下是具体修正方案:

核心问题分析

Twitch的VTuber目录内容在特定容器内实现无限滚动,默认的infiniteScroll()会监听整个页面滚动,但主页面的内容加载容器并非全局body;同时缺少滚动后的等待逻辑,导致滚动未触发内容加载就提前执行了链接入队操作。

修正后的代码

import {
  Dataset,
  createPlaywrightRouter,
  enqueueLinks,
  playwrightUtils,
} from "crawlee";

export const router = createPlaywrightRouter();

router.addDefaultHandler(
  async ({ log, page, request, infiniteScroll }) => {
    log.debug(`Processing: ${request.url}`);
    // 等待频道卡片容器加载完成
    await page.waitForSelector('[data-testid="directory-page__card-grid"]');
    
    // 配置infiniteScroll,针对Twitch的内容容器滚动
    await infiniteScroll({
      // 指定Twitch的频道列表容器作为滚动目标
      scrollTarget: '[data-testid="directory-page__card-grid"]',
      // 每次滚动的距离(适配Twitch的卡片高度)
      scrollDownBy: 800,
      // 滚动后等待新内容加载的时间
      waitForScrollStop: 2000,
      // 最大滚动次数(可根据需求调整)
      maxScrolls: 5,
    });

    // 滚动完成后,入队所有频道详情链接
    await enqueueLinks({
      selector: '[data-a-target="preview-card-image-link"]',
      label: "detail",
    });
  }
);

router.addHandler("detail", async ({ request, page, log }) => {
  log.debug(`Extracting data: ${request.url}`);

  await page.waitForSelector('[id="live-channel-about-panel"]');
  const instagram = await page
    .locator('a[role="link"][href*="instagram"]')
    .getAttribute("href");
  const twitter = await page
    .locator('a[role="link"][href*="twitter"]')
    .getAttribute("href");
  const discord = await page
    .locator('a[role="link"][href*="discord"]')
    .getAttribute("href");

  const results = { 
    url: request.url,
    instagram, 
    twitter, 
    discord 
  };

  // 将结果保存到Dataset(原代码漏了这一步,数据不会持久化)
  await Dataset.pushData(results);
  log.debug(results);
});

关键修改点说明

  • 指定滚动目标容器:通过scrollTarget参数定位Twitch的频道列表容器,确保滚动逻辑作用在正确区域。
  • 调整滚动参数:设置scrollDownBy控制每次滚动距离,waitForScrollStop等待新内容加载完成,maxScrolls限制滚动次数避免无限滚动。
  • 修正链接选择器:用更稳定的[data-a-target="preview-card-image-link"]选择频道链接,替代原有的动态类选择器(Twitch类名可能随时变化)。
  • 添加数据持久化:新增await Dataset.pushData(results),将抓取的数据保存到Dataset(原代码仅做日志输出,数据不会留存)。

备选手动滚动方案

如果内置infiniteScroll仍不生效,可尝试手动模拟滚动:

// 替换infiniteScroll的手动滚动逻辑
const scrollContainer = page.locator('[data-testid="directory-page__card-grid"]');
for (let i = 0; i < 5; i++) {
  await scrollContainer.evaluate(el => el.scrollBy(0, 800));
  await page.waitForTimeout(2000);
  // 等待新卡片加载完成
  await page.waitForSelector('[data-a-target="preview-card-image-link"]', { state: 'attached' });
}

内容的提问来源于stack exchange,提问作者Syed Hasnain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 02:52:33