如何用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
相关产品推荐
相关产品推荐

