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(视频与PPT)
Dec 27 Javascript
基于jQuery实现点击同时更改两个iframe的网址
Jul 01 Javascript
如何将网页表格内容导入excel
Feb 18 Javascript
JS 对象属性相关(检查属性、枚举属性等)
Apr 05 Javascript
浅析AngularJs HTTP响应拦截器
Dec 28 Javascript
浅析Node.js实现HTTP文件下载
Aug 05 Javascript
详解Node.Js如何处理post数据
Sep 19 Javascript
JS搜狐面试题分析
Dec 16 Javascript
javascript 显示全局变量与隐式全局变量的区别
Feb 09 Javascript
详解基于vue的移动web app页面缓存解决方案
Aug 03 Javascript
vue使用video插件vue-video-player的示例
Oct 03 Javascript
如何vue使用el-table遍历循环表头和表体数据
Apr 26 Vue.js
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实现可自定义样式的分页类
2016/03/29 PHP
PHP中explode函数和split函数的区别小结
2016/08/24 PHP
轻松实现php文件上传功能
2017/02/17 PHP
jquery 插件 web2.0分格的分页脚本,可用于ajax无刷新分页
2008/12/25 Javascript
JavaScript和CSS通过expression实现Table居中显示
2013/06/28 Javascript
简单讲解AngularJS的Routing路由的定义与使用
2016/03/05 Javascript
jQuery解决浏览器兼容性问题案例分析
2016/04/15 Javascript
javascript中使用未定义变量或值的情况分析
2016/07/19 Javascript
BootStrap中Datepicker控件带中文的js文件
2016/08/10 Javascript
D3.js实现文本的换行详解
2016/10/14 Javascript
js倒计时小实例(多次定时)
2016/12/08 Javascript
原生JavaScrpit中异步请求Ajax实现方法
2017/11/03 Javascript
详解ECMAScript typeof用法
2018/07/25 Javascript
使用Node.js实现一个多人游戏服务器引擎
2019/03/13 Javascript
windows10系统中安装python3.x+scrapy教程
2016/11/08 Python
Python制作刷网页流量工具
2017/04/23 Python
Python基于opencv实现的简单画板功能示例
2019/03/04 Python
python实现Dijkstra算法的最短路径问题
2019/06/21 Python
python实现代码统计器
2019/09/19 Python
keras model.fit 解决validation_spilt=num 的问题
2020/06/19 Python
哪种Python框架适合你?简单介绍几种主流Python框架
2020/08/04 Python
提供世界各地便宜的机票:Sky-tours
2016/07/21 全球购物
Tripadvisor新西兰:阅读评论,比较价格和酒店预订
2018/02/10 全球购物
具有防紫外线功能的高性能钓鱼服装:Hook&Tackle
2018/08/16 全球购物
英国时尚和家居用品零售商:Matalan
2021/02/28 全球购物
文秘专业应届生求职信范文
2013/11/14 职场文书
旷课检讨书1000字
2014/02/14 职场文书
工作睡觉检讨书
2014/02/25 职场文书
竞选班长演讲稿400字
2014/08/22 职场文书
2015年物业管理工作总结
2015/04/23 职场文书
如何写新闻稿
2015/07/18 职场文书
《狼王梦》读后感:可怜天下父母心
2019/11/01 职场文书
Python一行代码实现自动发邮件功能
2021/05/30 Python
JavaScript高级程序设计之基本引用类型
2021/11/17 Javascript
星际争霸:毕姥爷vs解冻01
2022/04/01 星际争霸
永中文档在线转换预览基于nginx配置部署方案
2022/06/10 Servers