如何下载JavaScript生成的Blob格式PDF?Chrome PDF Viewer访问问题
解决Playwright下载Blob格式PDF的问题
先修正你原有代码的错误
你之前的代码里,Promise.all中传入了await page.click("xpath=//button[@ng-click='yes()']"),这会导致点击操作在waitForEvent开始监听之前就执行了,自然捕获不到下载事件。正确的写法写法是直接传递page.click()返回的Promise:
async function playwrightDownload(page){ const [download] = await Promise.all([ page.waitForEvent('download'), page.getByRole('button', {name: 'Download PDF'}).click(), page.click("xpath=//button[@ng-click='yes()']") ]); await download.saveAs("test.pdf"); }
但这个写法可能还是无法触发download事件,因为Chrome会默认预览PDF而不是直接下载,下面是几个更可靠的方案:
方案1:拦截网络响应直接获取PDF内容
既然PDF是以Blob形式加载的,我们可以拦截页面的网络响应,直接提取PDF的二进制内容保存:
const fs = require('fs'); async function downloadBlobPDF(page) { let pdfBuffer = null; // 监听所有响应,筛选出PDF类型的Blob请求 const responseListener = async (response) => { const contentType = response.headers()['content-type']; if (response.url().startsWith('blob:') && contentType === 'application/pdf') { pdfBuffer = await response.body(); } }; page.on('response', responseListener); // 触发完整的下载流程 await page.getByRole('button', {name: 'Download PDF'}).click(); await page.click("xpath=//button[@ng-click='yes()']"); // 等待PDF内容获取完成 while (!pdfBuffer) { await page.waitForTimeout(100); } // 保存文件 fs.writeFileSync('test.pdf', pdfBuffer); // 移除监听避免内存泄漏 page.off('response', responseListener); }
方案2:禁用Chrome PDF预览,强制直接下载
通过修改Chrome的启动参数,禁止PDF预览功能,这样点击下载时浏览器会直接触发download事件而不是打开预览窗口:
const { chromium } = require('playwright'); async function initBrowser() { const browser = await chromium.launch({ args: [ '--disable-pdf-viewer', // 禁用内置PDF查看器 '--plugins=0', // 关闭插件支持 '--download-restrictions=0' // 取消下载限制 ] }); const page = await browser.newPage(); return { browser, page }; } // 之后使用修正后的下载函数 async function playwrightDownload(page){ const [download] = await Promise.all([ page.waitForEvent('download'), page.getByRole('button', {name: 'Download PDF'}).click(), page.click("xpath=//button[@ng-click='yes()']") ]); await download.saveAs("test.pdf"); }
方案3:直接在页面内获取Blob内容并导出
如果PDF是前端JavaScript直接生成的(而非从后端接口获取),可以通过page.evaluate()在页面上下文里获取Blob的Base64编码,再传递到Node环境保存:
const fs = require('fs'); async function getGeneratedPDF(page) { // 触发下载流程,同时在页面内获取Blob内容 const pdfBase64 = await page.evaluate(async () => { // 这里需要根据页面实际逻辑调整,比如找到生成PDF的函数 // 假设页面中有一个返回Blob的generatePDF函数 const pdfBlob = await window.generatePDF(); // 将Blob转为Base64 return new Promise((resolve) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result.split(',')[1]); reader.readAsDataURL(pdfBlob); }); }); // 将Base64转为Buffer并保存 const pdfBuffer = Buffer.from(pdfBase64, 'base64'); fs.writeFileSync('test.pdf', pdfBuffer); }
内容的提问来源于stack exchange,提问作者Aleksandr Stanov
相关产品推荐
相关产品推荐

