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

Heroku上Puppeteer脚本获取stale数据问题求助

Puppeteer在Heroku下载Stale Data问题修复方案

问题现象

  • 在Heroku运行Puppeteer脚本,流程为:登录公司网站→导航至报表页面→点击触发AJAX请求的标签页加载对应数据
  • headless=false模式下,UI正常显示标签页切换后的新数据,但下载文件始终是页面初始加载的旧数据
  • 手动在服务器Chromium中点击下载按钮,可获取正确的新数据
  • 已尝试添加固定延迟、waitForRequestIdle等方法,问题仍存在;且脚本一周前可正常运行

可能原因

  1. AJAX请求未完全同步:标签页切换后UI渲染完成,但后端数据接口的响应未完全同步到下载按钮的绑定数据源
  2. AngularJS digest cycle未完成:页面基于AngularJS开发(代码中存在ng-click),自动点击操作可能在框架的更新周期完成前触发下载
  3. 原生click事件缺失上下文:使用page.evaluate中的原生click()未模拟完整用户交互,导致页面未触发正确的数据更新逻辑

修复方案与代码修改

1. 等待标签页切换的目标AJAX请求完成

替换固定延迟为监听并等待报表数据的AJAX请求完成,确保数据完全加载:

// 点击标签页前,监听目标数据请求(替换为实际接口关键词)
const dataRequest = page.waitForRequest(request => 
  request.url().includes('report-data') && request.method() === 'POST' // 根据实际请求调整
);

await page.waitForSelector('ul.nav.nav-tabs > li:nth-child(4) > a', { visible: true });
await page.click('ul.nav.nav-tabs > li:nth-child(4) > a');
await dataRequest; // 等待数据请求响应完成

2. 等待AngularJS框架更新周期完成

针对AngularJS页面,确保框架的$digest或$apply完成后再进行下一步操作:

await page.evaluate(async () => {
  await new Promise(resolve => {
    if (window.angular) {
      // 获取根作用域,等待异步更新完成
      const rootScope = angular.element(document.body).scope();
      rootScope.$applyAsync(resolve);
    } else {
      resolve();
    }
  });
});

3. 使用Puppeteer原生page.click替代原生DOM点击

避免在page.evaluate中直接调用click(),改用Puppeteer的page.click模拟完整用户交互:

// 替换原打开过滤器的evaluate代码
await page.waitForSelector('.col-3.col-md-6.text-right.ng-binding button:nth-child(3)', { visible: true });
await page.click('.col-3.col-md-6.text-right.ng-binding button:nth-child(3)');

// 替换原下载按钮的evaluate代码
await page.waitForSelector('.col-3.col-md-6.text-right.ng-binding button:nth-child(2)', { visible: true });
await page.click('.col-3.col-md-6.text-right.ng-binding button:nth-child(2)');

4. 等待数据元素可见确认

添加等待报表数据行出现的逻辑,确保页面已渲染新数据:

// 替换原delay(3000)
await page.waitForSelector('.report-table-row-class', { visible: true }); // 替换为实际数据行选择器

完整修改后代码示例

// 点击标签页并等待数据请求
const dataRequest = page.waitForRequest(request => 
  request.url().includes('report-data') && request.method() === 'POST'
);
await page.waitForSelector('ul.nav.nav-tabs > li:nth-child(4) > a', { visible: true });
await page.click('ul.nav.nav-tabs > li:nth-child(4) > a');
await dataRequest;

console.log(7)

// 打开过滤器(改用page.click)
await page.waitForSelector('.col-3.col-md-6.text-right.ng-binding button:nth-child(3)', { visible: true });
await page.click('.col-3.col-md-6.text-right.ng-binding button:nth-child(3)');

console.log(8)

// 勾选ActivityReference过滤器
await page.evaluate(() => {
  const labels = Array.from(document.querySelectorAll('label.form-check-label'));
  const targetLabel = labels.find(label => label.textContent.includes('ActivityReference'));
  if (targetLabel) targetLabel.click();
});

console.log(9)

// 关闭过滤器弹窗
await page.waitForSelector('button[ng-click="close()"]', { visible: true });
await page.click('button[ng-click="close()"]');

console.log(10)

// 等待Angular更新和数据渲染
await page.evaluate(async () => {
  await new Promise(resolve => {
    if (window.angular) {
      const rootScope = angular.element(document.body).scope();
      rootScope.$applyAsync(resolve);
    } else {
      resolve();
    }
  });
});
await page.waitForSelector('.report-table-row-class', { visible: true }); // 替换为实际选择器

// 触发下载(改用page.click)
await page.waitForSelector('.col-3.col-md-6.text-right.ng-binding button:nth-child(2)', { visible: true });
await page.click('.col-3.col-md-6.text-right.ng-binding button:nth-child(2)');

// 等待文件下载完成(可根据文件大小调整)
await page.waitForTimeout(5000);

额外检查点

  • 确认Heroku上的Chromium配置正确,添加启动参数:--no-sandbox --disable-setuid-sandbox --disable-dev-shm-usage
  • 检查下载路径的权限,确保Puppeteer有权限写入下载文件
  • 排查网站是否近期更新了前端逻辑,导致原有的选择器或交互逻辑失效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 09:12:32