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

调整Puppeteer自动滚动参数时出现TargetCloseError问题求助

动态滚动加载页面爬取时TargetCloseError问题排查与解决

问题描述

爬取一个向下滚动加载新元素的商品列表页面,编写的autoScroll函数能获取更多条目,但增大滚动延迟时间或滚动距离时,出现错误:

TargetCloseError: Protocol error (Runtime.callFunctionOn): Target closed

相关代码:

const puppeteer = require('puppeteer');
 
async function autoScroll(page) {
    await page.evaluate(async () => {
      await new Promise((resolve, reject) => {
        var totalHeight = 0;
        var distance = 100; 
        var timer = setInterval(() => {
          var scrollHeight = document.body.scrollHeight;
          window.scrollBy(0, distance);
          totalHeight += distance;
 
          if (totalHeight >= scrollHeight) {
            clearInterval(timer);
            resolve();
          }
        }, 100); 
      });
    });
  }
 
async function scrape() {
  const browser = await puppeteer.connect({ browserWSEndpoint: `wss://chrome.browserless.io` });
  const page = await browser.newPage();
  await page.goto('https://a201910091655256231033.szwego.com/static/index.html#/shop_detail/A201910091655256231033', {waitUntil: "networkidle0"});
  await autoScroll(page);
 
  let combinedData = [];
  const textElements = await page.$$('.word-break');
  const imageElements = await page.$$('.lazy');
 
  for (let i = 0; i < textElements.length; i++) {
    const text = await page.evaluate(el => el.textContent.trim(), textElements[i]);
    let imageUrl = null;
    if (i < imageElements.length) { 
      imageUrl = await page.evaluate(el => el.getAttribute('data-original').trim(), imageElements[i]);
    }
    combinedData.push({ text: text, imageUrl: imageUrl });
  }
  console.log(JSON.stringify(combinedData, null, 2), combinedData.length);
  await browser.close();
}
 
scrape().catch(console.error);

问题原因与解决办法

1. 远程浏览器连接超时

你使用的browserless.io远程浏览器服务存在连接超时限制,当page.evaluate中运行长时间异步逻辑(比如增大延迟后的滚动循环),会导致WebSocket连接断开,触发TargetCloseError。

解决方式:将滚动逻辑从浏览器端(page.evaluate内)移到Node端执行,拆分滚动步骤,每次滚动后等待页面稳定,避免长时间占用浏览器上下文。

2. 页面意外跳转或刷新

滚动过程中可能触发页面的某些行为(比如懒加载时的页面重定向、框架导航),导致当前页面目标被关闭。

解决方式:添加页面导航监听,排查是否有意外跳转:

page.on('framenavigated', (frame) => {
  console.log('页面跳转:', frame.url());
});

3. 优化滚动逻辑

重写autoScroll函数,在Node端控制滚动循环,每次滚动后等待元素加载或页面高度变化:

async function autoScroll(page) {
  let previousHeight = 0;
  while (true) {
    const currentHeight = await page.evaluate(() => document.body.scrollHeight);
    // 滚动到底部
    await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
    // 等待页面加载新内容,可根据页面调整等待时间或条件
    await page.waitForTimeout(500);
    // 检查高度是否变化,无变化则停止滚动
    if (currentHeight === previousHeight) break;
    previousHeight = currentHeight;
  }
}

4. 增加连接稳定性配置

连接browserless时,可添加超时相关配置,延长连接存活时间:

const browser = await puppeteer.connect({
  browserWSEndpoint: `wss://chrome.browserless.io`,
  defaultViewport: null,
  // 增加超时时间
  timeout: 60000
});

修改后的完整代码示例

const puppeteer = require('puppeteer');
 
async function autoScroll(page) {
  let previousHeight = 0;
  while (true) {
    const currentHeight = await page.evaluate(() => document.body.scrollHeight);
    await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
    // 根据页面加载速度调整等待时间
    await page.waitForTimeout(500);
    if (currentHeight === previousHeight) break;
    previousHeight = currentHeight;
  }
}
 
async function scrape() {
  const browser = await puppeteer.connect({
    browserWSEndpoint: `wss://chrome.browserless.io`,
    timeout: 60000
  });
  const page = await browser.newPage();
  
  // 监听页面跳转,排查意外行为
  page.on('framenavigated', (frame) => {
    console.log('页面导航:', frame.url());
  });
  
  await page.goto('https://a201910091655256231033.szwego.com/static/index.html#/shop_detail/A201910091655256231033', {waitUntil: "networkidle0"});
  await autoScroll(page);
 
  let combinedData = [];
  const textElements = await page.$$('.word-break');
  const imageElements = await page.$$('.lazy');
 
  for (let i = 0; i < textElements.length; i++) {
    const text = await page.evaluate(el => el.textContent.trim(), textElements[i]);
    let imageUrl = null;
    if (i < imageElements.length) { 
      imageUrl = await page.evaluate(el => el.getAttribute('data-original').trim(), imageElements[i]);
    }
    combinedData.push({ text: text, imageUrl: imageUrl });
  }
  console.log(JSON.stringify(combinedData, null, 2), combinedData.length);
  await browser.close();
}
 
scrape().catch(console.error);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 06:27:14