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

Node、Puppeteer、Cheerio爬取动态页面时每页结果重复问题

问题分析与修复方案

你的代码核心问题是静态DOM复用,加上几处异步逻辑错误,导致每次循环都读取第一页的数据:

核心错误:复用了初始页面的cheerio DOM

你在循环外通过page.evaluate获取了第一次页面的HTML,并用cheerio加载成$,之后每次循环都用这个静态的$查询元素——它不会同步页面后续的动态更新,所以不管页面怎么变化,你读取的始终是第一页的内容。

其他问题

  1. cheerio的each方法不支持async/await,你写的async回调不会被等待,会导致还没读完当前页数据就跳转到下一页。
  2. Promise.all里的await page.waitForTimeout(5000)写法错误,会先阻塞5秒再执行点击,失去了并行等待的作用。
  3. 固定等待5秒不可靠,应该等待页面内容实际更新,而不是硬等时间。

修复后的代码

try {
    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();
    await page.goto(url, { waitUntil: "networkidle0" }).catch(err => console.log("error loading url", err));

    // 这里假设你已正确获取总页数pageCount,比如从分页栏提取
    // 示例:const pageCount = await page.evaluate(() => { /* 提取总页数的逻辑 */ });

    for (let i = 0; i < pageCount; i++) {
        // 等待当前页商品列表加载完成
        await page.waitForSelector('.itemDivWrapper > div');

        // 直接在浏览器上下文采集最新页面数据
        const itemNames = await page.evaluate(() => {
            const items = Array.from(document.querySelectorAll('.itemDivWrapper > div'));
            return items.map(item => {
                const h3 = item.querySelector('a > div > h3');
                return h3 ? h3.textContent.trim() : '';
            });
        });

        // 输出当前页商品名
        itemNames.forEach(name => console.log(name));

        // 最后一页无需点击下一页
        if (i < pageCount - 1) {
            await Promise.all([
                page.click('div.itemList > nav > ul > li.nextButton > a'),
                // 根据页面加载方式选择等待逻辑:
                // 若点击触发页面跳转,用waitForNavigation
                page.waitForNavigation({ waitUntil: "networkidle0" }),
                // 若为AJAX无刷新加载,改用等待商品列表更新
                // page.waitForSelector('.itemDivWrapper > div', { timeout: 10000 })
            ]);
        }
    }

    await browser.close();
} catch (error) {
    console.log(error);
}

关键修改说明

  1. 直接在页面上下文采集数据:用page.evaluate在浏览器里直接查询当前最新的DOM,代替cheerio的静态解析,确保每次循环读取的是当前页面的内容。
  2. 正确处理异步逻辑:通过await等待数据采集完成后,再执行下一页操作,避免逻辑混乱。
  3. 可靠的页面更新等待:根据页面加载方式,选择waitForNavigation(页面跳转场景)或waitForSelector(AJAX无刷新场景)代替固定等待,确保页面内容更新后再继续。
  4. 避免多余操作:循环到最后一页时,不再执行下一页点击。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 14:55:20