前端使用puppeteer 爬虫生成《React.js 小书》PDF并合并

若川大约 7 分钟

前端使用puppeteer 爬虫生成《React.js 小书》PDF并合并

写于2018年08月29日

大家好,我是若川open in new window。我倾力持续组织了一年每周大家一起学习200行左右的源码共读活动open in new window,感兴趣的可以点此扫码加我微信 ruochuan02 参与open in new window。另外,想学源码,极力推荐关注我写的专栏《学习源码整体架构系列》open in new window,目前是掘金关注人数(4.1k+人)第一的专栏,写有20余篇源码文章。

1、puppeteer 是什么?

puppeteer: Google 官方出品的 headless Chrome node
puppeteer github仓库open in new window
puppeteer APIopen in new window

官方介绍:

您可以在浏览器中手动执行的大多数操作都可以使用Puppeteer完成!

生成页面的屏幕截图和PDF
抓取SPA并生成预渲染内容(即“SSR”)。
自动化表单提交,UI测试,键盘输入等。
创建最新的自动化测试环境。使用最新的JavaScript和浏览器功能直接在最新版本的Chrome中运行测试。
捕获时间线跟踪 您的网站,以帮助诊断性能问题。
测试Chrome扩展程序。

2、爬取网站生成PDF

2.1 安装 puppeteer

# 安装 puppeteer
# 可能会因为网络原因安装失败,可使用淘宝镜像
# npm install -g cnpm --registry=https://registry.npm.taobao.org
npm i puppeteer
# or "yarn add puppeteer"

2.2 《React.js小书》简介

React.js小书》open in new window简介
关于作者@胡子大哈open in new window
这是⼀本关于 React.js 的⼩书。 因为⼯作中⼀直在使⽤ React.js,也⼀直以来想总结⼀下⾃⼰关于 React.js 的⼀些 知识、经验。于是把⼀些想法慢慢整理书写下来,做成⼀本开源、免费、专业、简单 的⼊⻔级别的⼩书,提供给社区。希望能够帮助到更多 React.js 刚⼊⻔朋友。
下图是《React.js 小书》部分截图: 《 小书》部分截图

2.3 一些可能会用到的 puppeteer API

// 新建 reactMiniBook.js, 运行 node reactMiniBook.js 生成pdf
const puppeteer = require('puppeteer');

(async () => {
  // 启动浏览器
  const browser = await puppeteer.launch({
        // 无界面 默认为true,改成false,则可以看到浏览器操作,目前生成pdf只支持无界面的操作。
        // headless: false,
        // 开启开发者调试模式,默认false, 也就是平时F12打开的面版
		// devtools: true,
  });
  // 打开一个标签页
  const page = await browser.newPage();
  // 跳转到页面 http://huziketang.mangojuice.top/books/react/
  await page.goto('http://huziketang.com/books/react/', {waitUntil: 'networkidle2'});
  // path 路径, format 生成pdf页面格式
  await page.pdf({path: 'react.pdf', format: 'A4'});
  // 关闭浏览器
  await browser.close();
})();

知道这启动浏览器打开页面关闭浏览器主流程后,再来看几个API

const args = 1;
let wh = await page.evaluate((args) => {
    // args 可以这样传递给这个函数。
    // 类似于 setTimeout(() => {console.log(args);}, 3000, args);
    console.log('args', args); // 1
    // 这里可以运行 dom操作等js
    // 返回通过dom操作等获取到的数据
    return {
        width: 1920,
        height: document.body.clientHeight,
    };
}, args);
// 设置视图大小
await page.setViewport(wh);
// 等待2s
await page.waitFor(2000);
// 以iPhone X执行。
const devices = require('puppeteer/DeviceDescriptors');
const iPhone = devices['iPhone X'];
await page.emulate(iPhone);

2.4 知道了以上这些API后,就可以开始写主程序了。

简单说下:实现功能和主流程。从上面React.js小书截图来看。
1、打开浏览器,进入目录页,生成0. React 小书 目录.pdf
2、跳转到1. React.js 简介页面,获取左侧所有的导航a链接的href,标题。
3、用获取到的a链接数组进行for循环,这个循环里主要做了如下几件事:

3.1 隐藏左侧导航,便于生成pdf
3.2 给**React.js简介**等标题 加上序号,便于查看
3.3 设置docment.title 加上序号, 便于在页眉中使用。
3.4 隐藏 传播一下知识也是一个很好的选择 这一个模块(因为页眉页脚中设置了书的链接等信息,就隐藏这个了)
3.5 给 分页 上一节,下一节加上序号,便于查看。
3.6 最末尾声明下该pdf的说明,仅供学习交流,严禁用于商业用途。
3.7 返回宽高,用于设置视图大小
3.8 设置视图大小,创建生成pdf

4、关闭浏览器

具体代码:可以查看这里爬虫生成《React.js小书》的pdf每一小节的代码open in new window

// node 执行这个文件
// 笔者这里是:
node src/puppeteer/reactMiniBook.js

即可生成如下图:每一小节(0-46小节)的pdf

每一小节(0-46小节)的
每一小节(0-46小节)的pdf

生成这些后,那么问题来了,就是查看时总不能看一小节,打开一小节来看,这样很不方便。
于是接下来就是合并这些pdf成为一个pdf文件。

3、合并成一个PDF文件 pdf-merge

起初,我是使用在线网站Smallpdfopen in new window,合并PDF。合并的效果还是很不错的。这网站还是其他功能。比如wordpdf等。
后来找到社区提供的一个npm packagepdf mergeopen in new window。 (毕竟笔者是写程序的,所以就用代码来实现合并了)

这个pdf-merge依赖 pdftkopen in new window

安装 PDFtk
Windows
下载并安装open in new window
笔者安装后,重启电脑才能使用。

Debian, Ubuntu 安装
笔者在Ubuntu系统安装后,即可使用。
apt-get install pdftk

使用例子

const PDFMerge = require('pdf-merge');

const files = [
	`${__dirname}/1.pdf`,
	`${__dirname}/2.pdf`,
];

// Buffer (Default)
PDFMerge(files)
.then((buffer) => {...});

// Stream
PDFMerge(files, {output: 'Stream'})
.then((stream) => {...});

// 笔者这里使用的是这个
// Save as new file
PDFMerge(files, {output: `${__dirname}/3.pdf`})
.then((buffer) => {...});

知道这些后,可以开始写主程序了。
简单说下主流程
1、读取到生成的所有pdf文件路径,并排序(0-46)
2、判断下输出文件夹是否存在,不存在则创建
3、合并这些小节的pdf保存到新文件 React小书(完整版)-作者:胡子大哈-时间戳.pdf

具体代码:可以查看这里爬虫生成《React.js小书》的pdf合并pdf的代码open in new window

最终合并的pdf文件在这里React小书(完整版)-作者:胡子大哈open in new window,可供下载。

本想着还可以加下书签和页码,没找到合适的生成方案,那暂时先不加了。如果读者有好的方案,欢迎与笔者交流。

小结

1、puppeteerGoogle 官方出品的 headless Chrome node库,可以在浏览器中手动执行的大多数操作都可以使用Puppeteer完成。总之可以用来做很多有趣的事情。
2、用 puppeteer 生成每一小节的pdf,用依赖pdftkpdf-merge npm包, 合并成一个新的pdf文件。或者使用Smallpdfopen in new window等网站合并。
3、React.js小书》open in new window,推荐给大家。爬虫生成pdf,应该不会对作者@胡子大哈open in new window有什么影响。作者写书服务社区不易,尽可能多支持作者。

最后推荐几个链接,方便大家学习 puppeteer
puppeteer入门教程open in new window
Puppeteer 初探之前端自动化测试open in new window
爬虫生成ES6标准入门 pdfopen in new window
大前端神器安利之 Puppeteeropen in new window
puppeteer API中文文档open in new window

关于

作者:常以若川为名混迹于江湖。前端路上 | PPT爱好者 | 所知甚少,唯善学。
个人博客open in new window
掘金专栏open in new window,欢迎关注~
segmentfault前端视野专栏open in new window,开通了前端视野专栏,欢迎关注~
知乎前端视野专栏open in new window,开通了前端视野专栏,欢迎关注~
github blogopen in new window,相关源码和资源都放在这里,求个star_~

微信公众号 若川视野

可能比较有趣的微信公众号,长按扫码关注。也可以加微信 ruochuan12,注明来源,拉您进【前端视野交流群】。

若川视野
若川视野
欢迎扫码加我微信
拉你进源码共读群
一起学习源码