快捷搜索:

金沙第一娱乐娱城官网

当前位置:金沙第一娱乐娱城官网 > 金沙第一娱乐娱城官网 > 在客户端和服务器端都可以生成PDF文件,和其他

在客户端和服务器端都可以生成PDF文件,和其他

来源:http://www.dlksamusic.com 作者:金沙第一娱乐娱城官网 时间:2020-01-25 16:31

浏览器开发人员工具为网站和Web应用程序的底层提供了许多惊人的选择。这些功能可以通过第三方工具进一步增强和自动化。在本文中,我们将研究Puppeteer,这是一个用于Chrome / Chromium的基于节点的库。

时间: 2019-03-31阅读: 421标签: pdf

Puppeteer的GitHub链接 本文是对该链接的翻译,扩充解释和举例说明

Puppeteer 是谷歌公司最近推出的基于Node开发的一套高级API库,通过开发协议来控制无界面的浏览器。

通俗的说就是有这么一套API, 可以用来控制浏览器的行为,比如打开网页,查看控件/文本,填入文字,点击按钮,滑动屏幕. 而这个浏览器可以是不显示界面的 (这对于在命令行情况下的运行非常方便)

一个Node库,它提供了高级API来通过DevTools协议控制Chrome或Chromium。Puppeteer默认情况下无头运行,但可以配置为运行完整的Chrome或Chromium。

金沙娱场app下载,在本文中,我将展示如何使用 Node.js、Puppeteer、headless Chrome 和 Docker 从样式复杂的 React 页面生成 PDF 文档。

我能用这套API干嘛呢?

几乎所有你能在浏览器上做的事情, 通过调用puppeteer API 也能够实现, 比如:

  • 生成浏览器页面的屏幕截图或者是pdf文件
  • 方便的抓取单页面和预渲染页面的信息内容
  • 网站爬虫
  • 自动化执行页面提交,UI自动化测试,键盘输入等.
  • 可以建立基于最新Chrome和Javascript的测试环境
  • 抓取并跟踪网站的执行时间轴,帮助分析效率问题

Puppeteer由Google Chrome背后的团队开发,因此您可以肯定它将得到很好的维护。它使我们能够通过一个简单易用的API通过JavaScript以编程方式在Chromium浏览器上执行常见操作。

背景:几个月前,一个客户要求我们开发一个功能,用户可以得到 PDF 格式的 React 页面内容。该页面基本上是患者病例的报告和数据可视化结果,其中包含许多 SVG。另外还有一些特殊的请求来操纵布局,并对 HTML 元素进行一些重新排列。因此与原始的 React 页面相比,PDF 中应该有不同的样式和额外的内容。

入门指南

使用Puppeteer,您可以:

由于这个任务比用简单的 CSS 规则解决要复杂得多,所以我们先探讨了可能的实现方法。我们找到了 3 个主要解决方案。这篇博文将指导你了解它们的可能性并最终实施。

安装

*注意: Puppeteer最低要求Node版本v6.4.0, 但是下面的例子中出现的 async/await 的用法最低要求Node版本v7.6.0

在node工程中使用Puppeteer, (添加依赖库) 执行 :

yarn add puppeteer
# or "npm i puppeteer"

*注意: 安装Puppeteer的时候会安装最新版本的Chromium ( 预估大小 ~71Mb Mac, ~90Mb Linux, ~110Mb Win) 来确保API可以执行. 如果你确定不需要下载,请设置 环境变量.

生成网站截图,包括SVG和Canvas

在客户端还是服务器端生成?

使用

Puppeteer 和其他驱动浏览器来执行测试的框架(Casperjs, Selenium 笔者: 以后会分别写文章介绍)类似. 你创建一个浏览器的实例,打开页面,通过Puppeteer's API 操作页面上的元素.

举例 - 访问 https://example.com 并保存页面截图为 example.png:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch(); // 创建浏览器实例
  const page = await browser.newPage(); // 创建新的浏览器页面
  await page.goto('https://example.com'); //  页面访问地址 http://example.com
  await page.screenshot({path: 'example.png'}); // 页面截图 example.png

  await browser.close(); // 关闭浏览器
})();

Puppeteer 设置浏览器页面为 800像素 x 600像素, 屏幕截图也依据这个大小. 如你需要调整页面大小,可以通过 Page.setViewport().

举例 - 创建PDF.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://news.ycombinator.com', {waitUntil: 'networkidle2'}); 
  await page.pdf({path: 'hn.pdf', format: 'A4'});

  await browser.close();
})();

上例中waitUntil表示等待的时长,参数定义在这里waitUntil

  • 搜索waitUntil
    Page.pdf() 访问这里有更多关于创建PDF的信息.

举例 - 通过页面上下文 (context) 获取页面信息

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');

  // Get the "viewport" of the page, as reported by the page.
  const dimensions = await page.evaluate(() => { // 通过evaluate执行页面js
    return {
      width: document.documentElement.clientWidth, // 页面宽度
      height: document.documentElement.clientHeight, // 页面高度
      deviceScaleFactor: window.devicePixelRatio // 设备像素比
    };
  });

  console.log('Dimensions:', dimensions);

  await browser.close();
})();

访问 Page.evaluate() 获得更多关于 evaluate 和相关功能例如 evaluateOnNewDocument and exposeFunction的介绍。

使用标准DOM API访问网页并提取信息

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

默认的运行设置

1. 使用无界面模式

Puppeteer 运行 Chromium in 无界面模式. 如果你需要运行一个完整的 Chromium, 在创建浏览器的时候请设置 'headless' 选项

const browser = await puppeteer.launch({headless: false}); // 默认为true

2. 自定义运行的 Chromium

默认情况下, Puppeteer 会选择自行选择下载 Chromium 来确保其API 在当前环境下正常运行. 如果确认需要运行不同版本的 Chromium, 在创建浏览器的时候传入executablePath参数,值为目标浏览器的可执行路径:

const browser = await puppeteer.launch({executablePath: '/path/to/Chrome'});

3. 创建新的用户信息

Puppeteer 会自动创建Chromium 用户信息,同时 每次执行完都清除.

生成预渲染的内容-即服务器端渲染

即便如此,我仍然会展示这两种方法的解决方案。

API 文档

完整 API 文档 和 例子.

像Cypress一样自动化UI测试

方案1:从 DOM 制作屏幕截图

调试技巧

  1. 显示界面 - 最直观的调试方法就是看到界面上发生了什么. 通过创建完整浏览器来实现,选项 headless: false:

    const browser = await puppeteer.launch({headless: false});
    
  2. 让执行慢下来 - slowMo 选项 可以指定毫秒值,让 Puppeteer 的执行慢下来 ,也对调试有帮助

    const browser = await puppeteer.launch({
      headless: false,
      slowMo: 250 // slow down by 250ms
    });
    
  3. 获取Console的输出 - 你既可以监听 console 事件, 也可以通过 page.evaluate()来打印。

    page.on('console', msg => console.log('PAGE LOG:', ...msg.args));
    
    await page.evaluate(() => console.log(`url is ${location.href}`));
    
  4. 启用详细日志 - 所有API调用和内部协议交互都会被记录在 puppeteer 名字空间的 debug 模式下.

    # 所有详细的日志
    env DEBUG="puppeteer:*" node script.js
    
    # 通过名字空间来控制调试日志的输出
    env DEBUG="puppeteer:*,-puppeteer:protocol" node script.js # 除了protocol外的所有消息
    env DEBUG="puppeteer:session" node script.js # 只需要protocol session 消息 
    env DEBUG="puppeteer:mouse,puppeteer:keyboard" node script.js # 只输出鼠标和键盘日志
    
    # Protocol 的交互消息会很多. 这里的例子说明了如何过滤掉所有Netwok的消息。
    env DEBUG="puppeteer:*" env DEBUG_COLORS=true node script.js 2>&1 | grep -v '"Network'
    

Puppeteer并没有Selenium,PhantomJS之类的东西做任何新的事情,但是它提供了一个简单易用的API,并提供了很好的抽象性,因此我们不必担心问题的实质。细节处理。

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

额外的例子

这些例子从 Issue 页面归纳而来,如果有额外的需要请留言。

  1. 如何模拟页面点击?

    通过以下page的接口, 相关 issue

    page.mouseMoved(x, y, options = {})
    page.mousePressed(x, y, options = {})
    page.mouseReleased(x, y, options = {})
    page.tap(x, y, options = {})
    page.touchmove()
    page.touchend()
    
  2. 如何上下翻动页面?

    通过调用page.evaluate中的 window.scrollBy来实现, 相关 issue

    page.evaluate(_ => { window.scrollBy(0, window.innerHeight);
    
  3. 避免页面ssl认证错误信息
    通过puppeteer option ignoredHTTPErrors 实现

  4. page.evalute 能否返回page DOM?
    你可以传入 ObjectHandle到page.evaluate中成为DOM元素,但当DOM被返回的时候则成 为对应的 ObjectHandle. issue
    如果需要返回,也可以返回实际需要的值,例如:

    const list = await page.evaluateHandle(() => {
    return Array.from(document.getElementsByTagName('a')).map(a => a.href);
    });
    console.log(await list.jsonValue());
    

    相关 iusse

  5. 如何读取和设置cookies?
    通过page.setCookie 和 page.cookies 接口。 目前有一些关于该功能的使用问题, 相关 issue

  6. 如何上传文件?
    通过elementHandle.uploadFile(...filePaths) 接口。 目前只支持 input type="file" 类
    型的文件提交。 相关issue

  7. 如何获得页面html代码?
    通过 page.content()

  8. 如何关闭javascript弹框
    通过 dialog.accept, 相关 issue

        page.on('dialog', dialog => {
            dialog.accept('test');
        });
    
  9. 如何监控页面的网络请求?

    const page = await browser.newPage();
    await page.setRequestInterceptionEnabled(true);
    
    page.on('request', request => {
      request.continue(); // pass it through.
    });
    
    page.on('response', response => {
      const req = response.request();
      console.log(req.method, response.status, req.url);
    });
    
  10. 如何输入内容?
    方法1 page.type

    // ...
    await page.focus('#lst-ib')
    page.type('China')
    // ...
    

    方法2 page.evaluate 后 element.value =

    await page.evaluate((a, b) => {
       document.querySelector('#a').value = a;
       document.querySelector('#b').value = b;
       document.querySelector('#c').click();
     }, a, b);
    
  11. 如何在页面中不同的Frame中切换
    通过page.frames()获得frame的数组,使用 iframe.$ 来获得对应frame中的handle
    例如:

    const browser = await puppeteer.launch({headless: false});
    const page = await browser.newPage();
    await page.setContent('<iframe></iframe>');
    
    // the page.frames()[0] is always a main frame.
    const iframe = page.frames()[1];
    // fetch the body element of the iframe
    const body = await iframe.$('body');
    // ...
    // do something with `body`..
    // ...
    browser.close();
    
  12. 获取element中的自定义属性值
    通过page.evaluate 然后使用object.getAttribute

await page.evaluate( (obj) => {
  return obj.getAttribute('data-src');
}, imgurlEle);

它也得到了积极的维护,因此Chromium支持ECMAScript的所有新功能。

此方法简单明了:从页面创建屏幕截图,并把它放到 PDF 文件中。非常直截了当。我们可以使用两个包来实现:

先决条件

Html2canvas,根据 DOM 生成截图jsPdf,一个生成PDF的库

对于本教程,您需要JavaScript,ES6 +和Node.js的基础知识。

开始编码:

您还必须已经安装了最新版本的Node.js的。

npm install html2canvas jspdf

yarn在本教程中,我们将一直使用。如果yarn尚未安装,请从此处安装。

import html2canvas from 'html2canvas'import jsPdf from 'jspdf' function printPDF () { const domElement = document.getElementById('your-id') html2canvas(domElement, { onclone: (document) = { document.getElementById('print-button').style.visibility = 'hidden'}}) .then((canvas) = { const img = canvas.toDataURL('image/png') const pdf = new jsPdf() pdf.addImage(imgData, 'JPEG', 0, 0, width, height) pdf.save('your-filename.pdf')})

为了确保我们在同一页面上,这些是本教程中使用的版本:

就这样!

Node 12.12.0

请注意html2canvas的onclone方法。当你在截图之前需要操纵 DOM(例如隐藏打印按钮)时,它是非常方便的。我看到过很多使用这个包的项目。但不幸的是,这不是我们想要的,因为我们需要在后端完成对 PDF 的创建工作。

yarn 1.19.1

方案2:只使用 PDF 库

puppeteer 2.0.0

NPM上有几个库,如 jsPDF(如上所述)或PDFKit。他们的问题是,如果我想使用这些库,我将不得不重新调整页面结构。这肯定会损害可维护性,因为我需要将所有后续更改应用到 PDF 模板和 React 页面中。

安装

请看下面的代码。你需要亲自手动创建 PDF 文档。你需要遍历 DOM 并找出每个元素并将其转换为 PDF 格式,这是一项繁琐的工作。必须找到一个更简单的方法。

要在项目中使用Puppeteer,请在终端中运行以下命令:

doc = new PDFDocumentdoc.pipe fs.createWriteStream('output.pdf')doc.font('fonts/PalatinoBold.ttf') .fontSize(25) .text('Some text with an embedded font!', 100, 100) doc.image('path/to/image.png', { fit: [250, 300], align: 'center', valign: 'center'}); doc.addPage() .fontSize(25) .text('Here is some vector graphics...', 100, 100) doc.end()
$yarnaddpuppeteer

这段代码段来自 PDFKit 文档。但是如果你的目标是直接生成一个 PDF 文件,而不是对一个已经存在的(并且不断变化的)HTML 页面进行转换,它还是很有用的。

注意:安装Puppeteer时,它会下载保证可与该API一起使用的Chromium的最新版本(〜170MB macOS,〜282MB Linux,〜280MB Win)。要跳过下载,请参阅环境变量。

最终方案3:基于 Node.js 的 Puppeteer 和 Headless Chrome

如果您不需要下载Chromium,则可以安装:puppeteer-core

什么是Puppeteer?其文档中写道:

$yarnaddpuppeteer-core

Puppeteer 是一个 Node 库,它提供了一个高级 API 来控制 DevTools 协议上的 Chrome 或 Chromium。 Puppeteer 默认以 headless 模式运行 Chrome 或 Chromium,但其也可以被配置为完整的(non-headless)模式运行。

puppeteer-core旨在成为Puppeteer的轻量级版本,用于启动现有的浏览器安装或连接到远程浏览器。确保您安装的puppeteer-core版本与您打算连接的浏览器兼容。

它本质上是一个可以从 Node.js 运行的浏览器。如果你读过它的文档,其中首先提到的就是你可以用 Puppeteer 来生成页面的截图和PDF。优秀!这正是我们想要的。

注意:仅从1.7.0版发布。puppeteer-core

先用npmi i puppeteer安装 Puppeteer,并实现我们的功能。

本文由金沙第一娱乐娱城官网发布于金沙第一娱乐娱城官网,转载请注明出处:在客户端和服务器端都可以生成PDF文件,和其他

关键词:

上一篇:没有了

下一篇:没有了