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

使用Puppeteer下载登录后页面中的500MB Gzip文件时出现ReferenceError错误的技术求助

解决方案:用Puppeteer处理登录后下载大Gzip文件

看起来你遇到了Puppeteer下载大文件的典型问题——浏览器上下文和Node.js上下文混淆导致的错误,我来帮你梳理清楚并给出可行方案:

首先,你的代码报错的核心原因是:page.evaluate()的回调函数运行在浏览器上下文中,而浏览器环境里并没有Node.js的https、fs这些核心模块,所以会抛出ReferenceError: https is not defined。

针对500MB的大文件,我推荐两种高效的解决思路:


思路一:获取登录Cookie后,用Node.js原生模块直接下载(最优)

这种方式避开了浏览器处理大文件的内存压力,直接用Node.js的流能力来处理下载,更稳定高效,非常适合大文件场景。

实现步骤:

  1. 用Puppeteer完成登录流程,获取当前页面的所有Cookie
  2. 将Cookie格式化为HTTP请求头需要的字符串
  3. 使用Node.js的https模块发起请求,通过流将文件写入本地

代码示例:

const puppeteer = require('puppeteer');
const https = require('https');
const fs = require('fs');
const { BASEURL, lastFile } = require('./your-config'); // 替换成你的实际配置

const downloadLargeFile = async () => {
  const browser = await puppeteer.launch({ headless: 'new' });
  const page = await browser.newPage();

  // 第一步:完成登录流程(替换成你的实际登录操作)
  await page.goto(`https://${BASEURL}/login`);
  await page.type('#username', '你的用户名');
  await page.type('#password', '你的密码');
  await page.click('#login-button');
  await page.waitForNavigation({ waitUntil: 'networkidle2' });

  // 第二步:提取登录后的Cookie,转为请求头格式
  const cookies = await page.cookies();
  const cookieHeader = cookies.map(cookie => `${cookie.name}=${cookie.value}`).join('; ');

  // 第三步:构建下载链接和输出路径
  const downloadUrl = `https://${BASEURL}${lastFile}`;
  const fileName = downloadUrl.substring(downloadUrl.lastIndexOf('/') + 1);
  const outputPath = `/tmp/${fileName}`;

  // 第四步:用Node.js流下载文件
  return new Promise((resolve, reject) => {
    const request = https.get(downloadUrl, {
      headers: {
        'Cookie': cookieHeader,
        'Accept-Encoding': 'gzip' // 确保支持Gzip压缩文件
      }
    }, (res) => {
      if (res.statusCode !== 200) {
        reject(new Error(`下载失败,状态码:${res.statusCode}`));
        return;
      }

      const writeStream = fs.createWriteStream(outputPath);
      res.pipe(writeStream);

      writeStream.on('finish', () => {
        writeStream.close();
        console.log(`文件已成功下载到:${outputPath}`);
        resolve(outputPath);
      });

      writeStream.on('error', (err) => {
        fs.unlink(outputPath, () => {}); // 删除未完成的损坏文件
        reject(err);
      });
    });

    request.on('error', (err) => {
      reject(err);
    });
  }).finally(() => {
    browser.close();
  });
};

// 调用执行
downloadLargeFile().catch(err => console.error(err));

思路二:配置Puppeteer允许浏览器直接下载

如果你更倾向于让浏览器处理下载流程,可以配置Puppeteer的下载行为,指定下载路径后模拟点击下载链接。不过要注意,大文件可能会占用较多浏览器内存,需要确保运行环境有足够资源。

代码示例:

const puppeteer = require('puppeteer');
const { BASEURL, lastFile } = require('./your-config');

const downloadViaBrowser = async () => {
  const browser = await puppeteer.launch({ headless: 'new' });
  const page = await browser.newPage();

  // 配置浏览器允许下载,并指定保存路径
  const downloadPath = '/tmp';
  await page._client.send('Page.setDownloadBehavior', {
    behavior: 'allow',
    downloadPath: downloadPath
  });

  // 完成登录流程(同思路一)
  await page.goto(`https://${BASEURL}/login`);
  // ... 这里替换成你的登录操作 ...
  await page.waitForNavigation({ waitUntil: 'networkidle2' });

  // 导航到文件列表页面,找到下载链接并点击
  await page.goto(`https://${BASEURL}/你的文件列表页面路径`); // 替换成实际列表页面URL
  await page.click(`a[href="${lastFile}"]`); // 替换成实际下载链接的选择器

  // 等待下载完成(实际项目建议用监听文件变化的方式,这里用简单等待做示例)
  await page.waitForTimeout(30000);

  console.log(`文件已下载到:${downloadPath}`);
  await browser.close();
};

downloadViaBrowser().catch(err => console.error(err));

补充说明:

  • 为什么fetch不适合?浏览器中的fetch获取大文件时,会先将整个文件加载到内存中转为Blob,500MB的文件很容易导致内存溢出;而Node.js的流是分块处理,内存占用极低,更适合大文件场景。
  • 生产环境更推荐思路一,不仅内存占用低,而且下载过程更可控,能方便地处理错误、断点续传等需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 11:17:44