如何从浏览器PDF预览保存/下载PDF?Playwright遇内容损坏问题
问题:Playwright保存在线PDF文件内容损坏的解决方案
目标是下载在线PDF文件(示例地址:https://www.cheat-sheets.org/saved-copy/http-response-codes-1.pdf),使用以下Playwright代码执行后,本地保存的PDF内容损坏,但浏览器预览显示正常。尝试过切换媒体类型(print/screen)、截图、触发ctrl+s均无效。
现有代码
const playwright = require('playwright'); (async () => { const browser = await playwright.chromium.launch(); const context = await browser.newContext(); const page = await context.newPage(); // await page.emulateMedia({ media: 'print' }); // Doesn't work also. await page.emulateMedia({ media: 'screen' }); await page.goto('https://www.cheat-sheets.org/saved-copy/http-response-codes-1.pdf'); console.log('Page Visited'); await page.waitForTimeout(3000); // To wait for the pdf to be full loaded. console.log('Timeout Done'); await page.pdf({ path: `document.pdf` }); console.log('Document Saved'); await browser.close(); })();
问题现象
- Playwright控制的浏览器预览PDF显示正常
- 本地保存的
document.pdf内容损坏,无法正常读取
解决方案
方案1:直接HTTP请求下载原PDF文件
page.pdf()是将网页渲染为PDF,而在线PDF是浏览器阅读器渲染的界面,并非普通HTML,因此该方法无法获取原文件。直接通过HTTP请求下载是最直接的方式:
const fetch = require('node-fetch'); const fs = require('fs').promises; (async () => { const pdfUrl = 'https://www.cheat-sheets.org/saved-copy/http-response-codes-1.pdf'; const response = await fetch(pdfUrl); if (!response.ok) { throw new Error(`请求失败:${response.status}`); } const pdfBuffer = await response.buffer(); await fs.writeFile('document.pdf', pdfBuffer); console.log('原PDF文件已成功下载'); })();
方案2:通过浏览器上下文触发下载(适用于需要验证的场景)
如果目标PDF需要登录或其他验证才能访问,可以配置浏览器拦截请求,修改响应头触发下载:
const playwright = require('playwright'); (async () => { const browser = await playwright.chromium.launch(); const context = await browser.newContext({ acceptDownloads: true // 开启下载支持 }); const page = await context.newPage(); // 拦截所有PDF请求,修改响应头触发下载 await page.route('**/*.pdf', async (route) => { const originalResponse = await route.fetch(); // 添加Content-Disposition头,让浏览器下载而非预览 const modifiedHeaders = { ...originalResponse.headers(), 'Content-Disposition': 'attachment; filename="document.pdf"' }; await route.fulfill({ response: originalResponse, headers: modifiedHeaders }); }); // 等待下载事件 const downloadPromise = page.waitForEvent('download'); await page.goto('https://www.cheat-sheets.org/saved-copy/http-response-codes-1.pdf'); const download = await downloadPromise; // 保存下载的文件到本地 await download.saveAs('document.pdf'); console.log('PDF已通过浏览器下载保存'); await browser.close(); })();
原因说明
page.pdf()方法的作用是将当前页面的HTML内容渲染生成PDF,而在线PDF是通过浏览器内置的PDF阅读器渲染展示的,本质上是阅读器的界面而非原PDF文件。因此用该方法保存的是阅读器的渲染结果,而非原文件,导致内容损坏。直接下载原文件或触发浏览器原生下载才能获取完整有效的PDF。
内容的提问来源于stack exchange,提问作者Jplus2
相关产品推荐
相关产品推荐

