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

使用Puppeteer+NestJS爬取网站时无法循环点击下一页

Puppeteer + NestJS 分页爬取问题解决(循环终止、数据提取失效)

核心问题根源

  • 循环仅执行一次:循环条件判断时机错误,或点击下一页后未等待DOM更新,误判已到最后一页
  • 第二页数据无法提取:单页应用切换分页后,原有DOM元素被销毁,未重新定位表格且未等待新数据加载
  • 截图未生成:截图时机过早(页面未渲染完成)或路径权限问题

解决方案步骤

  1. 等待页面更新再操作
    点击下一页后,不要立刻执行数据提取或条件判断,用waitForFunction或waitForSelector等待表格内容更新,避免操作未渲染完成的DOM。

  2. 修正循环条件逻辑
    不要提前判断下一页状态,需在提取完当前页数据后,动态查询下一页按钮的disabled属性(仅最后一页会添加该属性),确保判断的是实时状态。

  3. 重新定位DOM元素
    每一页加载完成后,重新查询表格行元素,不要复用之前的元素句柄——单页应用分页切换会重建DOM,旧句柄会失效。

  4. 调整截图时机
    在提取完当前页数据后执行截图,确保页面渲染完成,同时指定明确的文件路径(如带页码的文件名)。

修改后的NestJS服务代码示例

import { Injectable } from '@nestjs/common';
import puppeteer from 'puppeteer';

@Injectable()
export class ScraperService {
  async scrapeRcaData(): Promise<Array<{
    id: string;
    numeroImmatriculation: string;
    dateImmat: string;
    titre: string;
    refId: string;
  }>> {
    const browser = await puppeteer.launch({ headless: false }); // 调试时关闭无头模式,方便观察页面
    const page = await browser.newPage();
    await page.goto('https://rca.cnc.fr/rca.frontoffice/#', { waitUntil: 'networkidle2' });

    // 此处添加表单提交逻辑(你已实现的部分)
    // ...

    const allResults: Array<any> = [];
    let currentPage = 1;
    let hasNextPage = true;

    do {
      // 等待当前页表格加载完成
      await page.waitForSelector('table tbody tr'); // 替换为实际表格行选择器

      // 提取当前页数据
      const pageData = await page.evaluate(() => {
        const rows = Array.from(document.querySelectorAll('table tbody tr'));
        return rows.map(row => ({
          // 替换为实际DOM字段选择器
          id: row.querySelector('td:nth-child(1)').textContent.trim(),
          numeroImmatriculation: row.querySelector('td:nth-child(2)').textContent.trim(),
          dateImmat: row.querySelector('td:nth-child(3)').textContent.trim(),
          titre: row.querySelector('td:nth-child(4)').textContent.trim(),
          refId: row.querySelector('td:nth-child(5)').textContent.trim(),
        }));
      });

      allResults.push(...pageData);
      console.log(`已爬取第${currentPage}页,共${pageData.length}条数据`);

      // 生成当前页截图
      await page.screenshot({ path: `./screenshots/page-${currentPage}.png`, fullPage: true });

      // 动态判断是否有下一页
      hasNextPage = await page.$eval('.pagination-btn.next', btn => !btn.disabled); // 替换为实际下一页按钮选择器

      if (hasNextPage) {
        // 点击下一页并等待新数据加载
        await page.click('.pagination-btn.next');
        // 等待表格内容更新(确保新页数据已渲染)
        await page.waitForFunction(
          () => document.querySelectorAll('table tbody tr').length > 0,
          { timeout: 10000 }
        );
        currentPage++;
      }

    } while (hasNextPage);

    await browser.close();
    return allResults;
  }
}

关键注意事项

  • 选择器准确性:务必将代码中所有选择器(表格行、下一页按钮)替换为网站实际DOM选择器,可通过浏览器开发者工具查看
  • 等待策略:单页应用不要依赖waitForNavigation,无页面跳转时,用waitForFunction等待DOM内容变化更可靠
  • 调试技巧:开启headless: false,直观观察页面操作流程,排查点击失败、数据提取失效等问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 16:55:11