如何使用 puppeteer 和 Node js 为 pdf 页面生成屏幕截图

Posted

技术标签:

【中文标题】如何使用 puppeteer 和 Node js 为 pdf 页面生成屏幕截图【英文标题】:How to generate screenshots for pdf pages using puppeteer and Node js 【发布时间】:2019-09-30 08:49:54 【问题描述】:

我正在使用 puppeteer 和 node js 创建一个屏幕截图生成器。它适用于普通网页,但对于 pdf 页面,每次运行时它总是给出相同的错误

这是代码(https://github.com/GoogleChrome/puppeteer 的第一个示例)

const puppeteer = require('puppeteer');

(async () => 
    try 
        const browser = await puppeteer.launch();
        const page = await browser.newPage();
        await page.goto('https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf');
        await page.screenshot( path: 'example.png' );
        await browser.close();
     catch (err) 
        console.log(err);
    
)();

我得到的错误

Error: net::ERR_ABORTED at https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf
    at navigate (C:\MEAN\puppeteer-demo\node_modules\puppeteer\lib\FrameManager.js:121:37)
    at process._tickCallback (internal/process/next_tick.js:68:7)
  -- ASYNC --
    at Frame.<anonymous> (C:\MEAN\puppeteer-demo\node_modules\puppeteer\lib\helper.js:110:27)
    at Page.goto (C:\MEAN\puppeteer-demo\node_modules\puppeteer\lib\Page.js:629:49)
    at Page.<anonymous> (C:\MEAN\puppeteer-demo\node_modules\puppeteer\lib\helper.js:111:23)
    at C:\MEAN\puppeteer-demo\index.js:7:20
    at process._tickCallback (internal/process/next_tick.js:68:7)

感谢任何帮助。我也愿意接受任何其他可能的解决方案。

【问题讨论】:

您将无法从 PDF 中截取屏幕截图,因为 Chromium 没有创建目标。当 Chromium 加载一个 PDf 时,它正在加载一个 PDF 查看器,这不是目标开发人员工具可以调试的。 【参考方案1】:

对于现在遇到这个问题的任何人,我通过使用 Puppeteer、EJS 和 PDF.js 的组合来做到这一点,因为 puppeteer 本身不查看 PDF 文件。

我的方法基本上是使用 EJS 动态添加一个 URL,该 URL 将通过 PDF.js 查看,然后 puppeteer 将对其进行截图。

这里是 JS 部分

const ejs = require('ejs');
const puppeteer = require('puppeteer');

(async () => 
    const browser = await puppeteer.launch( 
        args: [
            '--disable-web-security',
            '--disable-features=IsolateOrigins',
            '--disable-site-isolation-trials'
        ]
    );
    const page = await browser.newPage();

    const url = "https://example.com/test.pdf";

    const html = await ejs.renderFile('./template.ejs',  data:  url  );

    await page.setContent(html);
    await page.waitForNetworkIdle();
    const image = await page.screenshot( encoding: 'base64' );

    await browser.close();

    console.log('Image: ', image);
)();

我在 puppeteer 启动中添加了 chromium args,以允许按照 this answer 不加载 pdf 文件。

这是 EJS 模板

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <style>
        body 
            width: 100vw;
            height: 100vh;
            margin: 0;
        
        #page 
            display: flex;
            width: 100%;
            height: 100%;
        
    </style>

    <title>Document</title>
</head>

<body>
    <canvas id="page"></canvas>
    <script src="https://unpkg.com/pdfjs-dist@2.0.489/build/pdf.min.js"></script>
    <script>
        (async () => 
            const pdf = await pdfjsLib.getDocument('<%= data.url %>');
            const page = await pdf.getPage(1);

            const viewport = page.getViewport(1);
        
            const canvas = document.getElementById('page');
            const context = canvas.getContext('2d');

            canvas.height = viewport.height;
            canvas.width = viewport.width;

            const renderContext = 
                canvasContext: context,
                viewport: viewport
            ;

            page.render(renderContext);
        )();
    </script>
</body>

</html>

请注意,此代码只会截取第一页的屏幕截图。

【讨论】:

【参考方案2】:

Chromium 不允许在 headless true 模式下打开 pdf 文件,请改用 headless false 模式。 await puppeteer.launch(args: ['--no-sandbox'], headless: false )

【讨论】:

【参考方案3】:

Headless Chrome 是 not able to visit PDF pages,并且会在您遇到时抛出错误 Error: net::ERR_ABORTED。虽然您可以使用headless: false 访问 PDF 文档,但截屏也会失败,因为 PDF 不是真正的网站,实际上是在单独的视图中呈现的。

替代方法

您可以做的是下载页面并使用PDF.js 创建页面的图像。您可能想查看有关“pdf 到图像”或“pdf 预览”主题的其他信息。关于该主题以及 examples on the PDF.js page 本身的 *** 有多个问题(1、2、..)。

【讨论】:

谢谢,我正在寻找一种下载 pdf 的方法,但这可能会为我节省很多时间。 你也可以只使用 PDF.js 来完成所有工作,这样你仍然可以在无头模式下做 puppeteer 的事情。您可以在同一脚本中同时使用 puppeteer 和 PDF.js。在选择使用哪一个之前,您可以/\.pdf$/.test( url )。我对 PDF.js 的探索还不足以了解它在下载和图像方面的所有功能,所以我不会谈论这个,但我已经能够结合使用它们来完成我自己的工作.

以上是关于如何使用 puppeteer 和 Node js 为 pdf 页面生成屏幕截图的主要内容,如果未能解决你的问题,请参考以下文章

使用Puppeteer将Node悬停在Node.js中的element和getComputedStyle上?

Node.js:如何重启 Tor 客户端

如何在 puppeteer Node.js 中将 const 添加到 await page.$eval?

使用 Puppeteer 和 Node.JS 在网站上的 iFrame 中找不到隐藏的输入元素

Node Js & Puppeteer - 如何选择包裹在 Anchor 标签内的文本

如何在 puppeteer Node.js 中将 const 添加到 await page.$x? xpath 中的常量