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

如何依次发起请求关联ID与图片,爬取认证XHR加载的资源

解决Puppeteer循环请求重复输出相同数据的问题

我有一组ID,需要关联对应图片。平时用Node.js的Axios+Cheerio串行发起请求,遇到需要认证的XHR/Fetch接口时,会用Puppeteer。目标是逐个处理每个ID,每行输出ID及对应的图片信息,期望输出格式如下:

030175020 null
800077125 <img src="//farmacialoreto.it/image/data/quarz-d30-weleda-polvere-20g.jpg" alt="Quarz D30 Weleda 20g">
                                    <span class="sale">-1%</span>

但当前的Puppeteer代码在第一次输出正确结果后,后续循环都会输出相同数据,原代码如下:

const puppeteer = require("puppeteer");

const baseUrl = 'https://farmacialoreto.it/#/dfclassic/query='
const arr = ["030175020","800075590",..."983757737"]

async function relateCodeToImg() {
  const browser = await puppeteer.launch({ headless: true })
  const page = await browser.newPage()

  for (const id of arr) {
    await page.goto(`${baseUrl}${id}`)
    
    if (await page.$eval('span[data-role="total"]', e => e.innerText) === "1") {
      console.log(id + " " + await page.$eval('figure[class="df-card__image image"]', e => e.innerHTML))
    } else {
      console.log(id + " " + null);
    }
    
  }
  await browser.close()
}
relateCodeToImg()

问题原因

核心问题是页面跳转后的等待机制不足,加上单页应用的路由切换可能存在缓存或DOM未完全更新的情况:

  • page.goto()默认只等待页面基本加载完成,但动态渲染的商品数据可能还没更新
  • 复用同一个页面时,旧的DOM内容或JS上下文没有被彻底重置,导致后续读取的是之前页面的缓存

解决方案

方案1:完善等待逻辑,确保内容完全更新

修改循环内的代码,增加网络空闲等待和元素加载等待,确保读取的是当前ID对应的最新内容:

const puppeteer = require("puppeteer");

const baseUrl = 'https://farmacialoreto.it/#/dfclassic/query='
const arr = ["030175020","800075590",..."983757737"]

async function relateCodeToImg() {
  const browser = await puppeteer.launch({ headless: true })
  const page = await browser.newPage()

  for (const id of arr) {
    // 等待网络空闲,确保所有请求完成
    await page.goto(`${baseUrl}${id}`, { waitUntil: 'networkidle2' });
    
    // 等待关键元素出现,避免读取不存在的内容
    await page.waitForSelector('span[data-role="total"]');
    
    const totalText = await page.$eval('span[data-role="total"]', e => e.innerText);
    if (totalText === "1") {
      // 等待图片元素加载完成
      await page.waitForSelector('figure[class="df-card__image image"]');
      const imgHtml = await page.$eval('figure[class="df-card__image image"]', e => e.innerHTML);
      console.log(`${id} ${imgHtml}`);
    } else {
      console.log(`${id} null`);
    }
  }
  await browser.close()
}
relateCodeToImg()

方案2:每次循环新建页面,彻底隔离上下文

如果单页应用的缓存问题无法通过等待解决,每次循环新建一个页面,用完即关闭,彻底避免上下文污染:

const puppeteer = require("puppeteer");

const baseUrl = 'https://farmacialoreto.it/#/dfclassic/query='
const arr = ["030175020","800075590",..."983757737"]

async function relateCodeToImg() {
  const browser = await puppeteer.launch({ headless: true })

  for (const id of arr) {
    // 每次循环新建页面
    const page = await browser.newPage();
    await page.goto(`${baseUrl}${id}`, { waitUntil: 'networkidle2' });
    
    const totalText = await page.$eval('span[data-role="total"]', e => e.innerText);
    if (totalText === "1") {
      const imgHtml = await page.$eval('figure[class="df-card__image image"]', e => e.innerHTML);
      console.log(`${id} ${imgHtml}`);
    } else {
      console.log(`${id} null`);
    }
    
    // 关闭当前页面,释放资源
    await page.close();
  }
  await browser.close()
}
relateCodeToImg()

关键优化点

  • { waitUntil: 'networkidle2' }:等待网络请求基本结束,确保动态数据加载完毕
  • page.waitForSelector():确保目标元素渲染完成后再读取内容,避免空值或旧数据
  • 新建页面:彻底隔离每个请求的上下文,解决单页应用的缓存问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 08:01:03