【问题标题】:Open Puppeteer with specific configuration (download PDF instead of PDF viewer)使用特定配置打开 Puppeteer(下载 PDF 而不是 PDF 查看器)
【发布时间】:2019-10-08 18:51:51
【问题描述】:

我想使用特定配置打开 Chromium。

我正在寻找配置to activate the following option

设置 => 站点设置 => 权限 => PDF 文档 => “下载 PDF 文件而不是在 Chrome 中自动打开它们”

我在this command line switch page 上搜索了标签,但处理pdf 的唯一参数是--print-to-pdf,这不符合我的需要。

你有什么想法吗?

【问题讨论】:

    标签: node.js puppeteer


    【解决方案1】:

    没有选项可以传递给 Puppeteer 来强制下载 PDF。但是,您可以使用 chrome-devtools-protocol 添加 content-disposition: attachment 响应标头来强制下载。

    您需要做的事情的可视化流程:

    我将在下面包含一个完整的示例代码。在下面的示例中,PDF 文件和 XML 文件将以 headful 模式下载。

    const puppeteer = require('puppeteer');
    
    (async () => {
      const browser = await puppeteer.launch({
        headless: false,
        defaultViewport: null, 
      });
    
      const page = await browser.newPage();
    
      const client = await page.target().createCDPSession();
    
      await client.send('Fetch.enable', {
        patterns: [
          {
            urlPattern: '*',
            requestStage: 'Response',
          },
        ],
      });
    
      await client.on('Fetch.requestPaused', async (reqEvent) => {
        const { requestId } = reqEvent;
    
        let responseHeaders = reqEvent.responseHeaders || [];
        let contentType = '';
    
        for (let elements of responseHeaders) {
          if (elements.name.toLowerCase() === 'content-type') {
            contentType = elements.value;
          }
        }
    
        if (contentType.endsWith('pdf') || contentType.endsWith('xml')) {
    
          responseHeaders.push({
            name: 'content-disposition',
            value: 'attachment',
          });
    
          const responseObj = await client.send('Fetch.getResponseBody', {
            requestId,
          });
    
          await client.send('Fetch.fulfillRequest', {
            requestId,
            responseCode: 200,
            responseHeaders,
            body: responseObj.body,
          });
        } else {
          await client.send('Fetch.continueRequest', { requestId });
        }
      });
    
      await page.goto('https://pdf-xml-download-test.vercel.app/');
    
      await page.waitFor(100000);
    
      await client.send('Fetch.disable');
    
      await browser.close();
    })();
    

    更详细的解释请参考我用cmets设置的Git repo。它还包括playwright 的示例代码。

    【讨论】:

    • 我已经尝试了很多解决方案,但在我的情况下只有这个工作,除了 await page.goto 抛出 net::ERR_ABORTED 错误。通过捕获错误并忽略它,然后验证本地路径中的文件以确认下载成功或不解决问题。
    【解决方案2】:

    Puppeteer 目前不支持导航(或下载)PDF 在无头模式下很容易。引用 page.goto 函数的文档:

    注意 无头模式不支持导航到 PDF 文档。请参阅upstream issue

    不过,您可以做的是检测浏览器是否正在导航到 PDF 文件,然后通过 Node.js 自行下载。

    代码示例

    const puppeteer = require('puppeteer');
    const http = require('http');
    const fs = require('fs');
    
    (async () => {
        const browser = await puppeteer.launch();
        const page = await browser.newPage();
    
        page.on('request', req => {
            if (req.url() === '...') {
                const file = fs.createWriteStream('./file.pdf');
                http.get(req.url(), response => response.pipe(file));
            }
        });
    
        await page.goto('...');
        await browser.close();
    })();
    

    这会导航到一个 URL 并监控正在进行的请求。如果找到“匹配的请求”,Node.js 将通过http.get 手动下载文件并将其通过管道传输到file.pdf。请注意,这是一个最小的工作示例。你想catch errors when downloading 并且可能还想使用比http.get 更复杂的东西,具体取决于具体情况。

    未来说明

    将来,可能会有更简单的方法来做到这一点。当 puppeteer 支持 response interception 时,您将能够简单地 force the browser to download 文档,但目前不支持此功能(2019 年 5 月)。

    【讨论】:

      猜你喜欢
      • 2019-04-03
      • 2016-07-23
      • 2019-09-24
      • 1970-01-01
      • 1970-01-01
      • 2022-01-22
      • 2018-07-05
      • 2021-03-09
      • 2013-06-23
      相关资源
      最近更新 更多