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

Node.js Puppeteer Core导航超时问题及爬取笔记本规格优化求助

爬取bhphotovideo.com笔记本规格的问题分析与解决方案

问题描述

作为网页爬取新手,在爬取bhphotovideo.com笔记本规格时遇到两类问题:

  1. 初始代码循环执行await page.waitForSelector(specSelector)时频繁触发TimeoutError: Navigation timeout of 30000 ms exceeded
  2. 参考修改代码后,爬取18个条目时出现ProtocolError: Target.attachToTarget timed out,任务失败

初始代码核心逻辑是复用单个页面跳转产品规格页,爬取后返回列表页;修改后改为循环创建新页面爬取,但引入了CDP会话处理验证码。

错误原因分析

初始代码超时原因

  • 单个页面反复跳转+page.goBack(),容易触发网站反爬机制,导致页面加载被限制
  • 默认30秒导航超时过短,部分产品规格页加载资源较多,无法在超时内完成
  • waitForSelector未设置合理超时,且未处理元素不存在的情况

修改后ProtocolError原因

  • 循环创建大量新页面+CDP会话,浏览器进程资源占用过高,导致Chrome DevTools Protocol连接不稳定
  • CDP会话创建时机错误:在page.goto()之前调用page.target().createCDPSession(),此时页面尚未完全初始化,容易触发连接超时
  • 未设置protocolTimeout,仅调整了导航超时,CDP命令本身的超时未覆盖
  • 固定5秒延迟不足以规避反爬,网站可能针对高频请求限制连接

具体解决方案

1. 优化页面资源使用,减少页面创建

复用单个页面进行爬取,避免频繁创建销毁页面导致的资源浪费:

// 初始化单个页面
const page = await browser.newPage();
page.setDefaultNavigationTimeout(2 * 60 * 1000);
page.setDefaultTimeout(2 * 60 * 1000);

// 爬取所有链接后,循环复用该页面
for (const [index, link] of allLinks.entries()) {
  try {
    await page.goto(`${link}/specs`, { waitUntil: "domcontentloaded", timeout: 60 * 1000 });
    // 等待规格元素加载,增加重试逻辑
    await page.waitForSelector("tr.pair_KqJ3Q3GPKv", { timeout: 60 * 1000 });
    
    // 验证码处理(如果需要)
    const client = await page.target().createCDPSession();
    const { status } = await client.send("Captcha.solve", { detectTimeout: 30 * 1000 });
    
    // 爬取逻辑...
  } catch (err) {
    console.error(`爬取${link}失败: ${err}`);
    // 失败后刷新页面,继续下一个
    await page.reload({ waitUntil: "domcontentloaded" });
    continue;
  }
}

2. 调整CDP会话创建时机

将CDP会话创建移至page.goto()之后,确保页面初始化完成:

// 错误写法:在goto前创建CDP
// const client = await page.target().createCDPSession();
// await page.goto(...)

// 正确写法
await page.goto(`${link}/specs`, { waitUntil: "domcontentloaded" });
const client = await page.target().createCDPSession(); // 页面加载完成后再创建会话

3. 完善全局超时设置

启动浏览器时设置protocolTimeout,覆盖CDP命令的超时限制:

const browser = await puppeteer.launch({
  // 其他配置
  protocolTimeout: 3 * 60 * 1000, // 设置为3分钟
});

4. 增强反爬规避策略

  • 随机延迟替代固定5秒延迟:
const randomDelay = () => new Promise(resolve => setTimeout(resolve, Math.random() * 5000 + 3000)); // 3-8秒随机延迟
// 在page.goto前调用
await randomDelay();
  • 设置真实用户代理:
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36');
  • 禁用图片和非必要资源加载,加快页面加载速度:
await page.setRequestInterception(true);
page.on('request', (req) => {
  if (['image', 'stylesheet', 'font', 'script'].includes(req.resourceType()) && !req.url().includes('bhphotovideo.com')) {
    req.abort();
  } else {
    req.continue();
  }
});

5. 优化错误处理逻辑

移除return语句,避免单个条目失败导致整个任务终止;增加重试机制:

// 初始代码中的错误处理
catch (error) {
  console.error(`Error occurred during scraping laptop ${i + 1}: ${error}`);
  // return; // 移除这个return,改为继续循环
  continue;
}

最终优化后核心代码示例

const puppeteer = require('puppeteer');
const urls = [/* 你的过滤页面链接 */];

const randomDelay = () => new Promise(resolve => setTimeout(resolve, Math.random() * 5000 + 3000));

const scrapeBHPhotoVideo = async () => {
  const browser = await puppeteer.launch({
    headless: 'new',
    protocolTimeout: 3 * 60 * 1000, // 设置CDP协议超时
  });
  const allLinks = [];

  // 第一步:爬取所有产品链接,复用页面
  const linkPage = await browser.newPage();
  await linkPage.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36');
  linkPage.setDefaultNavigationTimeout(2 * 60 * 1000);

  for (const url of urls) {
    await randomDelay();
    try {
      await linkPage.goto(url, { waitUntil: "domcontentloaded", timeout: 60 * 1000 });
      await linkPage.waitForSelector('a[data-selenium="miniProductPageProductNameLink"]', { timeout: 60 * 1000 });
      
      const links = await linkPage.evaluate(() => 
        [...document.querySelectorAll('a[data-selenium="miniProductPageProductNameLink"]')].map(link => link.href)
      );
      allLinks.push(...links);
    } catch (err) {
      console.error(`获取链接失败 ${url}: ${err}`);
      continue;
    }
  }
  await linkPage.close();

  // 第二步:爬取产品规格,复用单个页面
  const specPage = await browser.newPage();
  await specPage.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36');
  specPage.setDefaultNavigationTimeout(2 * 60 * 1000);
  specPage.setDefaultTimeout(2 * 60 * 1000);

  // 禁用非必要资源加载
  await specPage.setRequestInterception(true);
  specPage.on('request', (req) => {
    if (['image', 'font'].includes(req.resourceType())) {
      req.abort();
    } else {
      req.continue();
    }
  });

  for (const [index, link] of allLinks.entries()) {
    await randomDelay();
    try {
      await specPage.goto(`${link}/specs`, { waitUntil: "domcontentloaded", timeout: 60 * 1000 });
      await specPage.waitForSelector("tr.pair_KqJ3Q3GPKv", { timeout: 60 * 1000 });

      // 验证码处理(如果需要)
      const client = await specPage.target().createCDPSession();
      const { status } = await client.send("Captcha.solve", { detectTimeout: 30 * 1000 });
      console.log(`验证码状态: ${status}`);

      const specs = await specPage.evaluate(() => {
        const specs = {
          laptopbrand: document.querySelector('h1[data-selenium="productTitle"]')?.innerText || '',
          processor: '',
          cpu: '',
          gpu: '',
          graphics_type: '',
          ram: '',
          storage: '',
          display: '',
          resolution: '',
          refresh_rate: '',
          panel_type: '',
          built_in_speaker: '',
          built_in_microphone: '',
          network_io: '',
          usb_ports: '',
          webcam: '',
          cellular: '',
          bluetooth: '',
          wifi: '',
          battery: '',
          dimension: '',
          weight: '',
        };
        const rows = document.querySelectorAll("tr.pair_KqJ3Q3GPKv");
        rows.forEach((el) => {
          const label = el.querySelector("td.label_KqJ3Q3GPKv")?.textContent.trim() || '';
          const value = el.querySelector("td.value_KqJ3Q3GPKv span:not(.notSpecfMon)")?.textContent.trim() || '';
          switch (label) {
            case "Processor": specs.processor = value; break;
            case "CPU": specs.cpu = value; break;
            case "GPU": specs.gpu = value; break;
            case "Graphics Type": specs.graphics_type = value; break;
            case "Total Installed Memory": specs.ram = value; break;
            case "Total Installed Capacity": specs.storage = value; break;
            case "Display Size": specs.display = value; break;
            case "Resolution": specs.resolution = value; break;
            case "Refresh Rate": specs.refresh_rate = value; break;
            case "Panel Type": specs.panel_type = value; break;
            case "Built-In Speakers": specs.built_in_speaker = value; break;
            case "Built-In Microphones": specs.built_in_microphone = value; break;
            case "Network I/O": specs.network_io = value; break;
            case "Inputs/Outputs": specs.usb_ports = value; break;
            case "Webcam": specs.webcam = value; break;
            case "Cellular Support": specs.cellular = value; break;
            case "Bluetooth": specs.bluetooth = value; break;
            case "Wi-Fi": specs.wifi = value; break;
            case "Capacity": specs.battery = value; break;
            case "Dimensions": specs.dimension = value; break;
            case "Weight": specs.weight = value; break;
            default: break;
          }
        });
        return specs;
      });

      console.log(`已爬取第${index+1}个产品:`, specs);
      // 这里调用saveToDatabase
      // await saveToDatabase([specs], "Dell");
    } catch (err) {
      console.error(`爬取第${index+1}个产品失败 ${link}: ${err}`);
      // 失败后刷新页面,避免页面状态异常
      await specPage.reload({ waitUntil: "domcontentloaded" });
      continue;
    }
  }

  await specPage.close();
  await browser.close();
};

scrapeBHPhotoVideo();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 15:27:03