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

使用Puppeteer爬取YouTube直播SuperChat失效如何解决

问题原因

现有代码无法正常抓取YouTube SuperChat,核心是三个和YouTube页面逻辑相关的问题:

  • page.goto()默认仅等待页面load事件触发,YouTube直播聊天区是独立懒加载模块,load事件触发时聊天相关DOM节点还未渲染,查询操作自然拿不到结果
  • 你使用的#purchase-amount-chip选择器仅在SuperChat悬浮高亮的短暂时效内存在,不是SuperChat内容的常驻容器选择器,且Super Thanks、付费表情包的DOM结构和普通SuperChat完全分离
  • Puppeteer默认启动参数携带的自动化特征会被YouTube反爬机制识别,直接返回不带实时聊天模块的降级页面
可直接运行的修复版本

代码做了三处核心调整:启动时加反检测参数绕过YouTube自动化识别、等待聊天模块完全加载后再执行操作、通过DOM监听器持续捕获实时新增的SuperChat/付费表情包(后续扩展Super Thanks只需补充对应选择器即可),代码会自动把抓到的内容追加写入本地文件:

const puppeteer = require('puppeteer')
const fs = require("fs/promises")

async function start() {
    const browser = await puppeteer.launch({
        headless: "new",
        args: [
            '--disable-blink-features=AutomationControlled',
            '--start-maximized'
        ],
        defaultViewport: null
    })
    const page = await browser.newPage()
    // 注入脚本绕过webdriver特征检测
    await page.evaluateOnNewDocument(() => {
        Object.defineProperty(navigator, 'webdriver', {get: () => undefined})
    })
    // 等待网络请求空闲,确保聊天模块资源加载完成
    await page.goto("https://www.youtube.com/watch?v=1ykh6t3mec0", {
        waitUntil: 'networkidle2',
        timeout: 60000
    })
    // 显式等待聊天列表容器渲染完成
    await page.waitForSelector('#chat #items', {timeout: 30000})

    // 注册写入文件的方法,供页面上下文调用
    await page.exposeFunction('appendRecord', async (content) => {
        await fs.appendFile("superchats.txt", content + '\r\n')
    })

    await page.evaluate(() => {
        const chatContainer = document.querySelector('#chat #items')
        // SuperChat消息选择器
        const SUPER_CHAT_SELECTOR = 'yt-live-chat-paid-message-renderer'
        // 付费表情包(Super Stickers)选择器
        const SUPER_STICKER_SELECTOR = 'yt-live-chat-paid-sticker-renderer'

        // 解析单条付费内容并写入文件
        const parsePaidContent = (node) => {
            if (node.nodeType !== 1) return
            const timeStr = new Date().toLocaleString()
            // 解析普通SuperChat
            if (node.matches(SUPER_CHAT_SELECTOR)) {
                const user = node.querySelector('#author-name')?.textContent?.trim() || '未知用户'
                const amount = node.querySelector('#purchase-amount')?.textContent?.trim() || '未知金额'
                const msg = node.querySelector('#message')?.textContent?.trim() || '无文本内容'
                window.appendRecord(`[SuperChat ${timeStr}] 用户:${user} 金额:${amount} 内容:${msg}`)
            }
            // 解析付费表情包
            if (node.matches(SUPER_STICKER_SELECTOR)) {
                const user = node.querySelector('#author-name')?.textContent?.trim() || '未知用户'
                const amount = node.querySelector('#purchase-amount')?.textContent?.trim() || '未知金额'
                const stickerDesc = node.querySelector('#img')?.alt || '未知表情包'
                window.appendRecord(`[SuperSticker ${timeStr}] 用户:${user} 金额:${amount} 表情包:${stickerDesc}`)
            }
        }

        // 先抓取页面加载完成时已经存在的存量付费内容
        chatContainer.querySelectorAll(`${SUPER_CHAT_SELECTOR}, ${SUPER_STICKER_SELECTOR}`).forEach(parsePaidContent)
        // 注册DOM监听器,实时捕获后续新增的付费内容
        const observer = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
                mutation.addedNodes.forEach(parsePaidContent)
            })
        })
        observer.observe(chatContainer, {childList: true, subtree: true})
    })

    // *不要提前调用browser.close()*,保持浏览器运行持续抓取,不需要抓取时再手动关闭
}

start()
运行注意事项
  • 首次运行如果弹出YouTube Cookie同意弹窗,手动点击同意一次即可,后续启动会复用本地用户数据不需要重复操作
  • 如果进入直播间时聊天区是默认折叠状态,需要在代码里补充自动点击「显示聊天」按钮的逻辑,否则聊天容器不会渲染
  • 长时间运行建议加随机的行为模拟,不要一直挂着无操作,避免触发YouTube的反爬限制导致IP被临时封禁
  • 后续扩展Super Thanks支持时,只需要补充对应Super Thanks的DOM选择器,在parsePaidContent方法里加对应的解析逻辑即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 19:01:08