用Puppeteer和NodeJS将网页转换成PDF文件(附代码)

570 阅读5分钟

用Puppeteer和NodeJS将网页转换成PDF文件

作为一名Web开发者,你可能想把一个网页生成PDF文件,与你的客户分享,在演示文稿中使用,或者把它作为一个新的功能添加到你的Web应用程序中。无论你的理由是什么,Puppeteer,谷歌为无头Chrome和Chromium提供的Node API,让你的任务变得相当简单。

在本教程中,我们将看到如何用Puppeteer和Node.js把网页转换成PDF。让我们从快速介绍Puppeteer是什么开始工作。


什么是Puppeteer,为什么它很厉害?

用谷歌自己的话说,Puppeteer是:"一个Node库,它提供了一个高级API,可以通过DevTools协议控制无头的Chrome或Chromium"。

什么是无头浏览器?

如果你不熟悉无头浏览器这个词,它只是一个没有GUI的浏览器。从这个意义上说,无头浏览器只不过是另一个了解如何渲染HTML网页和处理JavaScript的浏览器。由于没有GUI,与无头浏览器的互动是通过命令行进行的。

尽管Puppeteer主要是一个无头浏览器,但你可以把它配置成非无头的Chrome或Chromium,并加以使用。

你能用Puppeteer做什么?

Puppeteer强大的浏览器功能使其成为网络应用程序测试和网络抓取的完美人选。

仅举几个使用案例,Puppeteer为Web开发者提供了完美的功能:

  • 生成网页的PDF和屏幕截图
  • 自动提交表单
  • 刮取网页
  • 执行自动UI测试,同时保持测试环境的最新状态。
  • 为单页面应用程序(SPA)生成预渲染的内容

设置项目环境

你可以在后端和前端使用Puppeteer来生成PDF。在本教程中,我们使用Node后端来完成这项任务。

初始化NPM,并设置常用的Express服务器,以开始教程的学习:

const express = require("express");
const puppeteer = require("puppeteer");
const app = express();

app.listen(3000, () => {
console.log("Server started");
});

在开始之前,请确保用以下命令安装Puppeteer NPM包:

npm install puppeteer

将网页转换为PDF

现在我们进入本教程的精彩部分。通过Puppeteer,我们只需要几行代码就可以将网页转换成PDF。

首先,使用 Puppeteer 的launch 函数创建一个浏览器实例:

const browser = await puppeteer.launch();

然后,我们创建一个新的页面实例,用Puppeteer访问给定的页面URL:

const webPage = await browser.newPage();

const url = "https://livecodestream.dev/post";

await webPage.goto(url, {
    waitUntil: "networkidle0"
});

我们将waitUntil 选项设置为networkidle0 。当我们使用networkidle0 选项时,Puppeteer会等待,直到最后500毫秒内没有新的网络连接。这是一种判断网站是否已经完成加载的方法。这并不准确,Puppeteer还提供了其他选项,但对于大多数情况来说,这是最可靠的方法之一。

最后,我们从抓取的页面内容中创建PDF,并将其保存到我们的设备中:

await webPage.pdf({
    printBackground: true,
    path: "webpage.pdf",
    format: "Letter",
    margin: {
        top: "20px",
        bottom: "40px",
        left: "20px",
        right: "20px"
    }
});

await browser.close();

打印成PDF的功能相当复杂,可以进行大量的定制,这非常好。下面是我们使用的一些选项。

  • printBackground:当这个选项设置为 "true "时,Puppeteer会将您在网页上使用的任何背景颜色或图像打印到PDF中。
  • 路径:路径指定了生成的PDF文件的保存位置。你也可以把它存储到一个内存流中,以避免写入磁盘。
  • 格式:你可以把PDF格式设置为给定的选项之一。Letter, A4, A3, A2, 等。
  • margin:你可以用这个选项为生成的PDF指定一个边距。

当PDF创建结束后,用browser.close() 关闭浏览器连接。


建立一个API,从URL生成和响应PDF

利用我们到目前为止收集到的知识,我们现在可以创建一个新的端点,它将接收一个URL作为查询字符串,然后它将把生成的PDF流返回给客户端。

下面是代码:

const express = require("express");
const puppeteer = require("puppeteer");
const app = express();

app.get("/pdf", async (req, res) => {
    const url = req.query.target;

    const browser = await puppeteer.launch({
        headless: true
    });

    const webPage = await browser.newPage();

    await webPage.goto(url, {
        waitUntil: "networkidle0"
    });
    
    const pdf = await webPage.pdf({
        printBackground: true,
        format: "Letter",
        margin: {
            top: "20px",
            bottom: "40px",
            left: "20px",
            right: "20px"
        }
    });

    await browser.close();

    res.contentType("application/pdf");
    res.send(pdf);
})

app.listen(3000, () => {
    console.log("Server started");
});

如果你启动服务器并访问/pdf 路径,用一个target 查询参数包含我们要转换的URL。服务器将直接提供生成的PDF,而不需要在磁盘上存储它。

URL的例子。http://localhost:3000/pdf?target=https://google.com

这将生成下面的PDF,因为它在图像上看起来:

捕获的PDF样本

这就是了!你已经完成了一个网页到PDF的转换。这不是很容易吗?

如前所述,Puppeteer提供了许多自定义选项,所以请确保你有机会玩一玩,以获得不同的结果。

接下来,我们可以改变视口大小,以捕获不同分辨率下的网站。


捕获不同视口的网站

在之前创建的PDF中,我们没有指定Puppeteer正在访问的网页的视口大小,而是使用了默认的视口大小,800×600px。

但是,我们可以在抓取网页之前精确地设置该网页的视口尺寸:

await webPage.setViewport({ width: 1200, height: 800 });


await webPage.goto(url, {
    waitUntil: "networkidle0"
});

总结

在今天的教程中,我们使用了Puppeteer,一个用于无头Chrome的Node API,来生成一个给定网页的PDF。由于你现在已经熟悉了Puppeteer的基础知识,你可以在未来使用这些知识来创建PDF,甚至用于其他目的,如网页抓取和UI测试。

谢谢你的阅读!