puppeteer库入门初探


Posted in Javascript onJanuary 09, 2019

puppeteer 是一个Chrome官方出品的headless Chrome node库。它提供了一系列的API, 可以在无UI的情况下调用Chrome的功能, 适用于爬虫、自动化处理等各种场景

根据官网上描述,puppeteer 具有以下作用:

  • 生成页面截图和 PDF
  • 自动化表单提交、UI 测试、键盘输入等
  • 创建一个最新的自动化测试环境。使用最新的 JavaScript 和浏览器功能,可以直接在最新版本的 Chrome 中运行测试。
  • 捕获站点的时间线跟踪,以帮助诊断性能问题。
  • 爬取 SPA 页面并进行预渲染(即'SSR')

以下就来阐述 puppeteer 的这几个作用

1.初始化项目

注: 这里我们会使用到 es6/7 的新特性,所以用 typescript 来编译代码

npm install puppeteer typescript @types/puppeteer

tsconfig.json 配置如下:

{
 "compileOnSave": true,
 "compilerOptions": {
  "target": "es5",
  "lib": [
   "es6", "dom"
  ],
  "types": [
   "node"
  ],
  "outDir": "./dist/",
  "sourceMap": true,
  "module": "commonjs",
  "watch": true,
  "moduleResolution": "node",
  "isolatedModules": false,
  "experimentalDecorators": true,
  "declaration": true,
  "suppressImplicitAnyIndexErrors": true
 },
 "include": [
  "./examples/**/*",
 ]
}

puppeteer 模块提供一个方法启动一个 Chromium 实例。

import * as puppeteer from 'puppeteer'

(async () => {
 await puppeteer.launch()
})()

上述代码通过 puppeteer 的 launch 方法生成一个 browser 实例,launch 方法可以接收一些配置项。较为常用的有:

  • headless [boolean]: 是否以 headless 模式启动浏览器
  • slowMo [number]: 减缓 puppeteer 的操作。这样就很方便的可以看到正在发生的事情
  • args[Array[string]]: 要传给浏览器实例的额外参数

2.生成页面截图

这里我们以 https://example.com/ 为例

(async () => {
 const browser = await puppeteer.launch(); //生成browser实例
 const page = await browser.newPage();   //解析一个新的页面。页面是在默认浏览器上下文创建的
 await page.goto("https://example.com/"); //跳转到 https://example.com/
 await page.screenshot({          //生成图片
  path: 'example.png'
 })
})()

在这里需要注意的是,截图默认截取的是打开网页可视区的内容,如果要获取完整的可滚动页面的屏幕截图,需要添加 fullPage: true

执行 node dist/screenshot.js ,即可在根目录下生成 example.png

puppeteer 默认将页面大小设置为 800*600,可以通过 page.setViewport() 来改变页面大小。

不仅如此,puppeteer 还可以模拟手机

import * as puppeteer from "puppeteer"; 
import * as devices from "puppeteer/DeviceDescriptors"; 
const iPhone = devices["iPhone 6"];

(async () => {
 const browser = await puppeteer.launch({
  headless: false
 });
 const page = await browser.newPage();
 await page.emulate(iPhone);
 await page.goto("https://baidu.com/");
 await browser.close();
})();

3.生成 pdf

(async () => {
 const browser = await puppeteer.launch();
 const page = await browser.newPage();
 await page.goto("https://example.com/");
 await page.pdf({
  displayHeaderFooter: true,
  path: 'example.pdf',
  format: 'A4',
  headerTemplate: '<b style="font-size: 30px">Hello world<b/>',
  footerTemplate: '<b style="font-size: 30px">Some text</b>',
  margin: {
   top: "100px",
   bottom: "200px",
   right: "30px",
   left: "30px",
  }
 });
 await browser.close();
})()

执行 node dist/pdf.js 即可。

4.自动化表单提交, 输入

在这里我们模拟一下京东的登录, 为了能更好的看到整个过程, 我们使用 headless: false 来关闭 headless 模式,看一下整个的登录流程

(async () => {
 const browser = await puppeteer.launch({
  headless: false
 });
 const page = await browser.newPage();
 await page.goto("https://github.com/login");
 await page.waitFor(1000)  //延迟1秒输入
 await page.type("#login_field", "1137060420@qq.com"); //立即输入
 await page.type("#password", "bian1992518", {
  delay: 100
 }) //模拟用户输入
 await page.click("input[type=submit]"); //点击登录按钮
})()

5.站点时间线追踪

可以很方便的使用 tracking.starttracking.stop 创建一个可以在 chrome devtools 打开的跟踪文件

(async () => {
 const broswer = await puppeteer.launch();
 const page = await broswer.newPage();
 await page.tracing.start({
  path: "trace.json"
 });
 await page.goto("https://example.com/");
 await page.tracing.stop();
 broswer.close();
})();

执行 node dist/trace.js 会生成一个 trace.json 文件, 然后我们打开 chrome devtools -> Performance, 然后把该文件直接拖进去即可。该功能便于我们对网站进行性能分析, 进而优化性能

6.爬虫和 SSR

现在大多数开发用 react、vue、angular 来构建 SPA 网站, SPA 固有很多的优点, 比方开发速度快、模块化、组件化、性能优等。但其缺点还是很明显的, 首先就是首屏渲染问题, 其次不利于 SEO, 对爬虫不友好。

以 https://preview.pro.ant.design/#/dashboard/analysis 为例, 我们点击右键, 查看源代码, 发现其 body 里面只有 <div id="root"></div> ,假如想把门店销售额排名情况给爬下来,存到数据库进行数据分析(如下图)

puppeteer库入门初探 

此时我们以传统爬虫的方式去爬的话是拿不到网页内容的。

如 python

# -*- coding : UTF-8 -*-
from bs4 import BeautifulSoup 
import urllib2


def spider(): 
  html = urllib2.urlopen('https://preview.pro.ant.design/#')
  html = html.read()
  soup = BeautifulSoup(html, 'lxml')
  print(soup.prettify())


if __name__ == '__main__': 
  spider()

执行 python py/index.py , 得到的结果如下图:

puppeteer库入门初探 

body 里面并没有页面相关的 dom,因此我们想通过 python 去爬取 SPA 页面的内容是不可行的。

nodejs

import axios from "axios";

(async () => {
 const res = await axios.get("https://preview.pro.ant.design/#");
 console.log(res.data);
})();

执行 node dist/node-spider.js , 得到和上面例子一样的结果。

puppeteer库入门初探

puppeteer

(async () => {
 const browser = await puppeteer.launch();
 const page = await browser.newPage();
 await page.goto("https://preview.pro.ant.design/#");
 console.log(await page.content());
})();

执行 node dist/spider.js , 得到如下:

puppeteer库入门初探 

此时我们可以惊奇的发现可以抓到页面所有的 dom 节点了。此时我们可以把它保存下来做 SSR,也可以爬取我们想要的内容了。

(async () => {
 const browser = await puppeteer.launch();
 const page = await browser.newPage();
 await page.goto("https://preview.pro.ant.design/#");
 const RANK = ".rankingList___11Ilg li";
 await page.waitForSelector(RANK);
 const res = await page.evaluate(() => {
  const getText = (v, selector) => {
   return v.querySelector(selector) && v.querySelector(selector).innerText;
  };
  const salesRank = Array.from(
   document.querySelectorAll(".rankingList___11Ilg li")
  );
  const data = [];
  salesRank.map(v => {
   const obj = {
    rank: getText(v, "span:nth-child(1)"),
    address: getText(v, "span:nth-child(2)"),
    sales: getText(v, "span:nth-child(3)")
   };
   data.push(obj);
  });
  return {
   data
  };
 });
 console.log(res);
 await browser.close();
})();

执行 node dist/spider.js , 得到如下:

puppeteer库入门初探

此时,我们已经利用 puppeteer 把我们所需要的数据给爬下来了。

到此,我们就把 puppeteer 基本的功能点给实现了一遍,本文示例代码可在 github 上获取。

参考

https://github.com/GoogleChrome/puppeteer
https://pptr.dev/#?product=Puppeteer&version=v1.6.0

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript写的简单的计算器,内容很多,方法实用,推荐
Dec 29 Javascript
jquery增加时编辑jqGrid(实例代码)
Nov 08 Javascript
原生javascript实现简单的datagrid数据表格
Jan 02 Javascript
jQuery插件EasyUI实现Layout框架页面中弹出窗体到最顶层效果(穿越iframe)
Aug 05 Javascript
Bootstrap模态框(modal)垂直居中的实例代码
Aug 18 Javascript
使用Vue.js创建一个时间跟踪的单页应用
Nov 28 Javascript
面包屑导航详解
Dec 07 Javascript
Angular 向组件传递模板的两种方法
Feb 23 Javascript
使用vue.js在页面内组件监听scroll事件的方法
Sep 11 Javascript
解决angularjs service中依赖注入$scope报错的问题
Oct 02 Javascript
发布一款npm包帮助理解npm的使用
Jan 03 Javascript
深入了解js原型模式
May 30 Javascript
node.js的Express服务器基本使用教程
Jan 09 #Javascript
JavaScript学习笔记之基于定时器实现图片无缝滚动功能详解
Jan 09 #Javascript
element-ui 时间选择器限制范围的实现(随动)
Jan 09 #Javascript
JavaScript学习笔记之DOM基础操作实例小结
Jan 09 #Javascript
如何解决webpack-dev-server代理常切换问题
Jan 09 #Javascript
JavaScript学习笔记之数组基本操作示例
Jan 09 #Javascript
浅谈webpack性能榨汁机(打包速度优化)
Jan 09 #Javascript
You might like
PHP设计模式之命令模式的深入解析
2013/06/13 PHP
php-fpm.conf配置文件中文说明详解及重要参数说明
2018/10/10 PHP
for 循环性能比较 提高for循环的效率
2009/03/19 Javascript
jquery实现文本框鼠标右击无效以及不能输入的代码
2010/11/05 Javascript
window.location.hash知识汇总
2015/11/09 Javascript
Javascript中this绑定的3种方法与比较
2016/10/13 Javascript
详解Javascript数据类型的转换规则
2016/12/12 Javascript
NodeJs入门教程之定时器和队列
2019/03/08 NodeJs
javascript实现切割轮播效果
2019/11/28 Javascript
JS实现轮播图效果
2020/01/11 Javascript
javascript实现随机抽奖功能
2020/12/30 Javascript
代码块高亮可复制显示js插件highlight.js+clipboard.js整合
2021/02/15 Javascript
[48:52]DOTA2上海特级锦标赛A组小组赛#2 Secret VS CDEC第一局
2016/02/25 DOTA
python模拟鼠标拖动操作的方法
2015/03/11 Python
在Python中使用itertools模块中的组合函数的教程
2015/04/13 Python
浅析Python 中整型对象存储的位置
2016/05/16 Python
Python简单实现安全开关文件的两种方式
2016/09/19 Python
python自动截取需要区域,进行图像识别的方法
2018/05/17 Python
python和shell获取文本内容的方法
2018/06/05 Python
Python实现自定义函数的5种常见形式分析
2018/06/16 Python
python numpy 按行归一化的实例
2019/01/21 Python
Python进程,多进程,获取进程id,给子进程传递参数操作示例
2019/10/11 Python
解决torch.autograd.backward中的参数问题
2020/01/07 Python
使用python的turtle函数绘制一个滑稽表情
2020/02/28 Python
Python小白不正确的使用类变量实例
2020/05/29 Python
CSS3 完美实现圆角效果
2009/07/13 HTML / CSS
viagogo意大利票务平台:演唱会、体育比赛、戏剧门票
2018/01/26 全球购物
英国第一家领先的在线处方眼镜零售商:Glasses Direct
2018/02/23 全球购物
《跨越百年的美丽》教学反思
2014/02/11 职场文书
《和田的维吾尔》教学反思
2014/04/14 职场文书
工伤事故赔偿协议书
2014/04/15 职场文书
反洗钱宣传活动总结
2014/08/26 职场文书
房屋授权委托书范本
2014/10/07 职场文书
文案策划岗位职责
2015/02/11 职场文书
学生通报表扬范文
2015/05/04 职场文书
运动会200米广播稿
2015/08/19 职场文书