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

Puppeteer抓取下载直链后如何在Node.js中通过fs模块下载文件

实现方案

你现有提取直链的逻辑不需要改动,只需要调整两部分配置和增加下载落盘逻辑即可:

  • 将Puppeteer启动参数的headless配置改为无头模式,全程不弹出浏览器窗口,提取到直链和必要的请求校验信息后即可直接关闭浏览器实例,不需要保持浏览器运行。
  • 拿到文件直链后,不通过page.click()触发浏览器下载,直接在Node.js侧发起HTTP请求拉取文件流,携带从页面上下文拿到的UA、Cookie、Referer信息绕过站点防盗链校验,最后通过fs模块将流写入自定义路径即可。

这种方案比监听Puppeteer下载事件的方式更灵活,不需要配置浏览器默认下载目录,也不需要额外做下载后的文件移动操作,大文件下载时用流写入也不会占用过高内存。

完整可运行代码
const fs = require('fs');
const https = require('https');
const http = require('http');
const path = require('path');
const puppeteer = require('puppeteer');

(async()=>{
    // 无头模式启动,无浏览器窗口
    const browser = await puppeteer.launch({
        headless: 'new',
        defaultViewport: false
    });

    const page = await browser.newPage();
    const url = `https://speed.hetzner.de/`;
    await page.goto(url, {"waitUntil": "networkidle2"});
    // 原有提取直链逻辑保持不变
    const downloadUrl = await page.$eval('p:nth-child(2) > a', elm => elm.href);
    console.log('提取到的文件直链:', downloadUrl);

    // 自定义存储路径,示例为当前目录下的downloads文件夹,可自行修改
    const saveDir = path.resolve(__dirname, './downloads');
    if (!fs.existsSync(saveDir)) {
        fs.mkdirSync(saveDir, { recursive: true });
    }
    // 自动从url解析文件名,也可自定义文件名
    const fileName = path.basename(new URL(downloadUrl).pathname);
    const savePath = path.join(saveDir, fileName);

    // 拿取页面上下文的请求头信息,绕过防盗链
    const userAgent = await page.evaluate(() => navigator.userAgent);
    const cookies = await page.cookies(downloadUrl);
    const cookieStr = cookies.map(item => `${item.name}=${item.value}`).join('; ');

    // 拿到必要信息后直接关闭浏览器,后续下载不需要浏览器参与
    await browser.close();

    // 流方式下载写入本地,支持大文件
    const requestClient = downloadUrl.startsWith('https') ? https : http;
    const writeStream = fs.createWriteStream(savePath);

    const sendRequest = (targetUrl) => {
        requestClient.get(targetUrl, {
            headers: {
                'User-Agent': userAgent,
                'Cookie': cookieStr,
                'Referer': url
            }
        }, (res) => {
            // 自动处理3xx重定向
            if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
                sendRequest(res.headers.location);
                return;
            }
            if (res.statusCode !== 200) {
                writeStream.destroy();
                fs.unlinkSync(savePath);
                console.error('下载失败,状态码:', res.statusCode);
                return;
            }
            res.pipe(writeStream);
        }).on('error', (err) => {
            writeStream.destroy();
            fs.existsSync(savePath) && fs.unlinkSync(savePath);
            console.error('请求失败:', err);
        });
    };

    sendRequest(downloadUrl);

    writeStream.on('finish', () => {
        writeStream.close();
        console.log(`文件下载完成,存储路径: ${savePath}`);
    });

    writeStream.on('error', (err) => {
        fs.existsSync(savePath) && fs.unlinkSync(savePath);
        console.error('文件写入失败:', err);
    });
})();
注意事项
  • 如果目标站点没有防盗链校验,可以省略拿Cookie、UA、Referer的步骤,直接请求直链即可。
  • 不想用原生http/https模块的话,也可以替换成axios等第三方请求库,记得将responseType设置为stream即可,落盘逻辑和上面一致。
  • 代码里默认自动创建存储目录、自动解析文件名,你可以根据业务需求修改为任意自定义路径和文件名。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 12:48:17