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

如何用Puppeteer拦截浏览器脚本发起的Blob请求?

如何拦截浏览器脚本发起的Blob类型请求?

我尝试过用Puppeteer拦截客户端生成的Blob下载,但按现有方法操作后,没能拦截到目标Blob请求。相关请求截图如下:

请求截图

我的代码如下:

import {Browser, connect, Page} from "puppeteer";
(async () => {
  const browser = await connect({
    browserURL: `http://127.0.0.1:4444`,
    ignoreHTTPSErrors: true,
  });

  const page = await browser.newPage();
  await page.setRequestInterception(true);

  page.on("request", async res => {
    // 自定义操作
  });
  page.on("response", async res => {
    // 自定义操作
  });

  const cdp = await page.target().createCDPSession();
  await cdp.send('Page.setDownloadBehavior', {
      behavior: 'allow',
      downloadPath: './'
  });
  // 未触发下载,说明Blob请求没被拦截
  cdp.on('Page.downloadWillBegin', ({ url, suggestedFilename }) => {
    // 自定义操作
  });
  // 未触发下载
  cdp.on('Page.downloadProgress', ({ state }) => {
    if (state === 'completed') {
      // 自定义操作
    }
  });
  const url = `https://amap.com`;
  await page.goto(url);
})()

解决方案

客户端生成的Blob下载不会触发常规的网络请求拦截(比如request/response事件),也不会触发Page.downloadWillBegin这类CDP事件——因为Blob是直接在浏览器内存里生成的,不走网络请求流程。要拦截这类操作,得通过重写浏览器端的Blob构造函数和相关下载API来实现:

方法1:重写Blob构造函数,直接捕获Blob内容

在页面加载前注入脚本,替换原生的Blob构造函数,这样所有生成Blob的操作都会被监控到:

// 在page.goto之前执行
await page.evaluateOnNewDocument(() => {
  const originalBlob = window.Blob;
  window.Blob = function(blobParts, options) {
    const blob = new originalBlob(blobParts, options);
    // 将Blob转为Base64并发送给Puppeteer
    const reader = new FileReader();
    reader.onload = function() {
      window.postMessage({ 
        type: 'BLOB_CAPTURE', 
        data: reader.result, 
        mimeType: options?.type 
      });
    };
    reader.readAsDataURL(blob);
    return blob;
  };
});

// 在Puppeteer中监听消息
page.on('message', (msg) => {
  if (msg.data.type === 'BLOB_CAPTURE') {
    console.log('捕获到Blob内容:', msg.data.data);
    // 这里可以把内容保存到本地文件,或者做其他处理
  }
});

方法2:拦截Blob下载触发链路(URL.createObjectURL + a标签)

如果Blob是通过创建下载链接触发的,可以重写URL.createObjectURL并监听a标签的点击事件:

await page.evaluateOnNewDocument(() => {
  const originalCreateObjectURL = window.URL.createObjectURL;
  window.URL.createObjectURL = function(blob) {
    const url = originalCreateObjectURL(blob);
    // 捕获Blob和对应的下载链接
    const reader = new FileReader();
    reader.onload = () => {
      // 尝试获取下载文件名
      const filename = document.querySelector(`a[href="${url}"]`)?.download || 'unknown-file';
      window.postMessage({ 
        type: 'BLOB_DOWNLOAD', 
        url, 
        data: reader.result,
        filename
      });
    };
    reader.readAsDataURL(blob);
    return url;
  };

  // 监听a标签的下载点击
  document.addEventListener('click', (e) => {
    const target = e.target.closest('a');
    if (target && target.href.startsWith('blob:')) {
      console.log('Blob下载链接被点击:', target.href);
    }
  });
});

方法3:用CDP Runtime监控Blob操作

如果需要更底层的监控,可以通过CDP的Runtime钩子跟踪Blob的创建:

const cdp = await page.target().createCDPSession();
await cdp.send('Runtime.enable');
await cdp.send('Runtime.setAsyncCallStackDepth', { maxDepth: 32 });

cdp.on('Runtime.consoleAPICalled', async (params) => {
  // 捕获页面中打印的Blob对象
  const blobArg = params.args.find(arg => arg.type === 'object' && arg.subtype === 'blob');
  if (blobArg) {
    const result = await cdp.send('Runtime.callFunctionOn', {
      objectId: blobArg.objectId,
      functionDeclaration: `function() {
        return new Promise(resolve => {
          const reader = new FileReader();
          reader.onload = () => resolve(reader.result);
          reader.readAsDataURL(this);
        });
      }`
    });
    console.log('通过CDP捕获到Blob:', result.result.value);
  }
});

关键提示

  • 客户端生成的Blob完全在本地处理,不会发起网络请求,所以常规的Puppeteer请求拦截方法无效。
  • 注入脚本重写原生API是最可靠的方案,所有生成Blob的操作都会经过这些API。
  • 如果Blob是通过Fetch/XHR请求转换而来的,直接在response事件中处理响应内容即可,不用等转换为Blob。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 00:10:27