首页 > 自考资讯 > 自考知识

将html转为pdf,怎么将html转换为pdf

头条共创 2024-06-27

本文向您展示如何使用Node.js、Puppeteer、headless Chrome 和Docker 从复杂风格的React 页面生成PDF 文档。

b640d52d-cd52-4410-94b8-89b53bbe1ac2~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1720073801&x-signature=p3mBKf2jKeQ272VroZa6yz8AKB0%3D 背景:几个月前,一位客户要求我开发一个功能,允许他以PDF 格式检索React 页面的内容。该页面本质上是患者病例报告和数据可视化,其中包含大量SVG。还有操作布局和执行HTML 元素重新定位的特殊要求。因此,与原始React 页面相比,PDF 中应该有不同的样式和附加内容。

这个任务比简单的CSS 规则复杂得多,所以让我们首先考虑可能的方法。我们找到了三个主要解决方案。这篇博文描述了它的潜力和最终实现。

目录:

是在客户端生成还是在服务器端生成? 选项1:从DOM 创建屏幕截图选项2:使用PDF 库最终选项3:Node.js、Puppeteer、Head 将响应Chrome 样式控制文件发送到客户端并使用Puppeteer 将其保存到Docker 选项3 +1:CSS 打印规则摘要是在客户端还是服务器端生成的?

PDF 文件可以在客户端和服务器端生成。但是,您不想用完用户浏览器可以提供的所有资源,因此让后端处理它可能更有意义。

不过,我将向您展示这两种方法的解决方案。

选项1:从DOM 创建屏幕截图

乍一看,这个解决方案似乎是最简单的,事实证明也是如此,但它有其自身的局限性。如果您没有特殊需求,例如在PDF 中选择文本或执行文本搜索,这是一种简单易用的方法。

该方法简单易行。从页面创建屏幕截图并将其保存为PDF 文件。这很容易。这可以使用两个包来完成。

Html2canvas,一个基于DOM生成截图jsPdf并生成PDF的库,开始编码。

npm 安装html2canvas jspdf

b195009efd594a93aaac22df95d1e356~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1720073801&x-signature=c1J8xOADSPDz%2FwriEZUqPfmfh1U%3D及以上!

注意html2canvas的onclone方法。如果您需要在截屏之前操作DOM(例如隐藏打印按钮),则非常有用。我见过很多项目都使用这个包。但不幸的是,这不是我们想要的,因为PDF 创建必须在后端完成。

选项2:使用PDF 库

NPM 有几个库,包括jsPDF(上面提到的)和PDFKit。问题是,如果我想使用这些库,我必须重建页面。这显然会对可维护性产生负面影响,因为所有后续更改都必须应用于PDF 模板和React 页面。

请参阅下面的代码。您必须自己手动创建PDF 文档。您必须遍历DOM 来查找每个元素并将其转换为PDF 格式,这是一项繁琐的任务。我必须找到一种更简单的方法。

6055fa463b554f649501a962d844f388~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1720073801&x-signature=%2Bkt9JkeJQQpEuglgBJuLMd96kp8%3D此代码片段来自PDFKit 文档。但是,如果您的目标是直接生成PDF 文件而不是转换现有(且不断变化的)HTML 页面,那么它仍然很有用。

最终选项3:基于Node.js 的Puppeteer 和Headless Chrome

什么是傀儡师?该文件说:

Puppeteer 是一个节点库,它提供了用于通过DevTools 协议控制Chrome 或Chromium 的高级API。 Puppeteer 默认以无头模式运行Chrome 或Chromium,但也可以配置为以完整(非无头)模式运行。

这本质上是一个可以从Node.js 运行的浏览器。如果您阅读该文档,它首先会说您可以使用Puppeteer 生成页面的屏幕截图和PDF。精彩的!这正是我们想要的。

首先,使用npmi i puppeteer 安装Puppeteer 并实现其功能。

ed45de021c114c739292c9b808abc10e~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1720073801&x-signature=nw%2Fnje6JqiFBEhFnlYHo7cdGF%2Bk%3D 这是一个简单的功能,可以导航到URL 并为您的站点生成PDF 文件。

首先,启动浏览器(仅在无头模式下支持PDF 生成),然后打开一个新页面,设置视口并导航到指定的URL。

当您设置waitUntil:'networkidle0' 选项时,如果至少500 毫秒没有网络连接,Puppeteer 就会认为导航完成。 (更多信息可从API 文档中获取。)

然后将PDF 保存为变量,关闭浏览器,然后返回到PDF。

注意:page.pdf 方法接受一个选项对象。您可以使用“路径”选项将文件保存到磁盘。如果未指定路径,PDF 将不会保存到磁盘,而是会进行缓冲。 (稍后我会解释如何处理这个问题。)

如果您在从受保护页面生成PDF 之前需要登录,则必须首先进入登录页面,验证并输入表单元素ID 或名称,然后提交表单。

522d7a14505a4226ac6be0c431f2da39~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1720073801&x-signature=Pdk%2BSgmub%2FrnS0xZfdGFFgkaIzM%3D 始终将登录凭据存储在环境变量中,而不是对其进行硬编码。

风格控制

Puppeteer 还为这种交互方式提供了解决方案。如果您在生成PDF 之前插入样式标签,Puppeteer 会生成一个包含修改后样式的文件。

wait page.addStyleTag({ content: '.nav { display: none} .navbar { border: 0px} #print-button {display: none}' }) 将文件发送到客户端并保存

现在后台已经生成了一个PDF文件。下一步是什么?

如上所述,如果您不将文件保存到磁盘,您最终会得到一个缓冲区。您需要做的就是将具有适当内容类型的缓冲区发送到前端。

b7436068870a46618b06467b162dc3c0~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1720073801&x-signature=rQi3kIhs%2FxHwGITi1J6H11mUAwo%3D现在,要获取生成的PDF,您只需在浏览器中向服务器发出请求即可。

d828eb03cd414ee19c56ccde09bc9884~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1720073801&x-signature=C9GTigc5wyX6Mv1EnRDAsX6R%2Fjs%3D 提交请求后,开始下载缓冲区内容。最后一步是将缓冲区数据转换为PDF 文件。

cf3993869b054d2a8ec07045ce8c3d4d~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1720073801&x-signature=2P0Y2p6jZ4fePwixlxEh3r%2BSrkk%3D 就是这样!单击“保存”按钮,您的浏览器将保存PDF。

将Puppeteer 与Docker 结合使用

我认为这是实现——最困难的部分,所以让我节省百度几个小时的时间。

官方文档指出*“使用Docker 运行无头Chrome 可能很困难”*。官方文档有一个故障排除部分,其中包含有关使用Docker 安装puppeteer 所需的所有信息。

如果您要在Alpine 映像上安装Puppeteer,请务必在看到页面的这一部分时向下滚动一点。否则,您可能会错过这样一个事实:您将无法运行最新版本的Puppeteer,并且需要使用标志禁用shm。

const browser=wait puppeteer.launch({ headless: true, args: ['--disable-dev-shm-usage']}); 否则,Puppeteer 子进程可能会在正常启动之前耗尽内存。

场景3+1:CSS打印规则

从开发人员的角度来看,人们可能会认为简单地使用CSS 打印规则会更容易。没有NPM 模块,只有纯CSS。但是跨浏览器兼容性怎么样?

选择CSS 打印规则时,您应该在所有浏览器中测试结果,以确保提供的布局相同,但这在100% 的情况下是不可能的。

例如,在特定元素后插入中断符并不是什么复杂的事情,但您可能会惊讶地发现在Firefox 中使用中断符需要一种解决方法。

除非您是一位经验丰富的CSS 高手,在创建可打印页面方面拥有丰富的经验,否则这可能会非常耗时。

当您可以保持打印样式表简单时,打印规则非常有用。

让我们看一个例子。

@media print { .print-button { display: none; } .content div { Break-after: always }} 上面的CSS 隐藏了打印按钮,并在每个包含内容类的div 之后插入分页符。这是一篇很棒的文章,概述了打印规则的功能以及打印规则的问题,包括浏览器兼容性。

考虑到所有因素,CSS 打印规则在从不太复杂的页面生成PDF 时效果非常好。

总结

让我们简要回顾一下前面介绍的从HTML 页面生成PDF 文件的场景。

从DOM 生成屏幕截图:当您需要从页面获取快照(例如创建缩略图)时,这很有用,但当您需要处理大量数据时,这可能会很困难。只需使用PDF 库即可。如果您计划从头开始以编程方式创建PDF 文件,那么这是完美的解决方案。否则,您将需要同时维护HTML 和PDF 模板,这是一个很大的禁忌。 Puppeteer:使用Docker 相对困难,但实现给了我们最好的结果,并且最容易编码。 CSS 打印规则:如果您的用户受过良好教育,了解如何将页面内容打印到文件,并且您的页面相对简单,那么这可能是最简单的解决方案。从我们的案例中可以看出,事实并非如此。今天是愚人节,以上所有内容均适用。

作者:疯狂科技极客

链接:https://juejin.im/post/5ca1dc0251882543d569e075

版权声明:本文由今日头条转载,如有侵犯您的版权,请联系本站编辑删除。

猜你喜欢