使用特定配置打开 Puppeteer(下载 PDF 而不是 PDF 查看器)

Jec*_*eck 5 node.js puppeteer

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

我正在寻找激活以下选项的配置:

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

我在这个命令行开关页面上搜索了标签,但唯一处理 pdf 的参数--print-to-pdf不符合我的需要。

你有什么想法?

小智 7

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

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

cdp-modify-response-header (2)

我将在下面包含一个完整的示例代码。在下面的示例中,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();
})();
Run Code Online (Sandbox Code Playgroud)

有关更详细的解释,请参阅我已设置的带有注释的Git 存储库。它还包括playwright的示例代码。


Tho*_*orf 2

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

注意无头模式不支持导航至 PDF 文档。请参阅上游问题

不过,您可以做的是检测浏览器是否正在导航到 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();
})();
Run Code Online (Sandbox Code Playgroud)

这会导航到 URL 并监视正在进行的请求。如果找到“匹配的请求”,Node.js 将通过管道手动下载文件http.get并将其传输到file.pdf. 请注意,这是一个最小的工作示例。您希望在下载时捕获错误http.get,并且可能还希望根据情况使用更复杂的东西。

未来笔记

将来,可能会有更简单的方法来做到这一点。当 puppeteer 支持响应拦截时,您将能够简单地强制浏览器下载文档,但目前不支持此功能(2019 年 5 月)。