首页 > 建站教程 > nodejs,electron >  Puppeteer 介绍及入门示例正文

Puppeteer 介绍及入门示例

本文转载自CSDN博主「夏狗花花」的原创文章,文章地址:https://blog.csdn.net/lychee_xiahua/article/details/119045640


Puppeteer 简介

Puppeteer 是一个Chrome官方团队提供的node库,它可以通过 Puppeteer 的提供的 API 直接控制 Chrome 或 Chromiun。


Puppeteer 可以做什么

1) 生成网页截图或者 PDF

2) 爬取SPA应用,并生成预渲染内容(即“SSR” 服务端渲染)

3) 高级爬虫,可以爬取大量异步渲染内容的网页

4) 模拟键盘输入、表单自动提交、登录网页等

5) 创建一个最新的自动化测试环境,实现 UI 自动化测试

6) 捕获站点的时间线,以便追踪网站、帮助分析网站性能问题

7) 用于测试 Chrome 扩展程序


运行环境

Nodejs 的版本不能低于 v7.6.0,因为需要支持 async, await.

需要最新的 chrome driver(安装 Puppeteer 时会自动下载)


Puppeteer 架构图

Puppeteer


Puppeteer API 是分层的,并反映了浏览器的结构。


    Puppeteer 使用 DevTools Protocol 与浏览器通信

    Browser 实例可以拥有多个浏览器上下文

    BrowserContext 实例定义了一个浏览会话,可以拥有多个页面

    Page 至少有一个 frame :main frame。可能还有其他由 iframe 创建的 frame 或标签

    Frame 至少有一个可执行上下文 - 默认执行上下文 - 在其中执行 frame 的 JavaScript 。一个 Frame 可能有与 extensions 有关联的其他执行上下文

    Worker 具有单个执行上下文,便于与 WebWorkers 交互


Puppeteer 初体验 —— 入门 Demo

官方入门 Demo 先感受一下基本用法:

const puppeteer = require('puppeteer');
(async () => {
  const browser = await puppeteer.launch(); //启动一个无头浏览器
  const page = await browser.newPage(); //打开一个标签页
  await page.goto('https://example.com'); //跳转到指定的页面
  await page.screenshot({path: 'example.png'}); // 对页面进行截图
  await browser.close(); //关闭浏览器
})();


Puppeteer 模块

Puppeteer 模块提供了一种启动 Chromium 实例的方法。


示例

启动一个浏览器

const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  await page.goto('https://www.google.com');
  // 其他操作...
  await browser.close();
});


puppeteer.launch([options])

可配置项(options)

属性类型说明默认值
ignoreHTTPSErrorsBoolean是否在导航期间忽略 HTTPS 错误false
headlessBoolean是否以无头模式运行浏览器true(除非 devtools 选项是 true)
devtoolsBoolean是否为每个选项卡自动打开DevTools面板false
timeoutNumber等待浏览器实例启动的最长时间(以毫秒为单位),设置 0 禁用超时30000(毫秒)
slowMoNumber将 Puppeteer 操作减少指定的毫秒数(为了方便调试)
※ defaultViewportObject为每个页面设置一个默认视口大小。如果为 null 的话就禁用视图口
dumpioBoolean是否将浏览器进程标准输出和标准错误输入到 process.stdoutprocess.stderrfalse

更多配置项参考官网


※ defaultViewport 可选参数

属性类型说明默认值
widthNumber页面宽度像素800
heightNumber页面高度像素600
deviceScaleFactorNumber设置设备的缩放(可以认为是 dpr)1
isMobileBoolean是否在页面中设置了 meta viewport 标签false
hasTouchBoolean指定viewport是否支持触摸事件false
isLandscapeBoolean指定视口是否处于横向模式false


puppeteer.connect(options)

这是将 Puppeteer 添加到已有的 Chromium 实例的方法。


可配置项(options)

属性类型说明默认值
browserWSEndpointString一个 浏览器 websocket 端点链接(必填)
ignoreHTTPSErrorsBoolean是否在导航期间忽略 HTTPS 错误false
defaultViewport*Object为每个页面设置一个默认视口大小。如果为 null 的话就禁用视图口
slowMoNumber将 Puppeteer 操作减少指定的毫秒数(为了方便调试)


Browser 对象

当 Puppeteer 连接到一个 Chromium 实例的时候会通过 puppeteer.launch 或 puppeteer.connect 创建一个 Browser 对象。


示例

示例1:使用 Browser 创建 Page

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

示例2:断开连接和重连到 Browser

const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
  // 存储节点以便能重新连接到 Chromium
  const browserWSEndpoint = browser.wsEndpoint();
  // 从 Chromium 断开和 puppeteer 的连接
  browser.disconnect();
  // 使用节点来重新建立连接
  const browser2 = await puppeteer.connect({browserWSEndpoint});
  // 关闭 Chromium
  await browser2.close();
});


Browser Methods

    browser.newPage():打开一个新的页面(创建一个新的 Page 对象)

    browser.disconnect():断开 Puppeteer 和浏览器的连接,但 Chromium 进程仍然在运行

    browser.close() :关闭 Chromium 及其所有页面

    browser.wsEndpoint():返回浏览器 websocket 的地址


page 对象

Page 提供操作一个 tab 页或者 extension background page(一个 chrome 拓展程序) 的方法。一个 Browser 实例可以有多个 Page 实例。


示例

示例1:创建一个 Page 实例,导航到一个 url ,然后保存截图

const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.screenshot({path: 'screenshot.png'});
  await browser.close();
});


示例2:用 on 或者 once 捕获 Page 事件,用 removeListener 移除事件监听

page.once('load', () => console.log('Page loaded!')); //捕获 page 实例的 load 事件
function logRequest(interceptedRequest) {
  console.log('A request was made:', interceptedRequest.url());
}
page.on('request', logRequest); //监听 request 事件
// 一段时间后...
page.removeListener('request', logRequest); //移除request监听


示例3:搜索并抓取图片

1、yarn add request


2、新建index.js

const puppeteer = require('puppeteer');
const request = require("request");
const fs = require('fs');
var scrape = async () => {
    // 初始化无头浏览器
    const browser = await puppeteer.launch({
        headless: false,
        defaultViewport: {
            width: 1200,
            height: 1000
        }
    });
    // 新建页面
    const page = await browser.newPage();
    //搜索关键字
    let word = '美女'
    // 跳转到指定页面
    await page.goto('https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=index&fr=&hs=0&xthttps=111110&sf=1&fmq=&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=' + word);
    await page.evaluate(function () {
    //该页面使用懒加载,滑动屏幕让图片加载
        window.scrollTo(0,1000)
        setTimeout(()=>{window.scrollTo(0,2000)},1000)
    })
    await page.waitForTimeout(3000)
    // 获取节点
    const data = await page.evaluate( ()=> {
    //拿到图片节点
        let dom = document.querySelectorAll('#imgid img')
        let arr = []
        for(let i=0;i<dom.length-1;i++){
            //去除base64格式
            if(!dom[i].src.includes('base64'))
            arr.push(dom[i].src) 
        }
        //返回图片链接
        return arr
    })
    //关闭浏览器
    browser.close()
    return data
}
scrape().then((value) => {
    for(let i = 1; i < value.length-1; i++) {
        let imgUrl = value[i];
        let filename = `${new Date().getTime()}imgage${i}.png`;
        //在C盘下创建文件夹
        fs.mkdir('C:/tempmeinv',(e)=>{
            if(!e || (e&&e).code === 'EEXIST'){
                if(imgUrl)
                //保存在这个目录下
                request(imgUrl).pipe(fs.createWriteStream("C:/tempmeinv/" + filename));
                else
                console.log('地址为空')
            }
            else{
                console.log('err')
            }
        })
    }
});


3、cmd 执行 node index.js


Page Events

page.on('load'):当页面的 load 事件被触发时触发

page.on('close'):当页面关闭时触发

page.on('request'):当页面发送一个请求时触发

page.on('response'):当页面的某个请求接收到对应的 response 时触发

page.on('error'):当页面崩溃时触发

page.on('console'):当页面js代码调用了 console 的某个方法时触发


Page Methods

基础类

page.goto(url[, options])导航到指定地址

page.close() 关闭页面

page.setViewport(viewport) 设置页面视口

page.evaluate(pageFunction[, ...args]) 在页面实例上下文中执行方法

page.setRequestInterception(value) 是否启用请求拦截器

cookie 类

page.cookies([...urls])返回指定页面域名的 cookie(若未指定url,返回当前页面域名的 cookie)

page.setCookie(...cookies) 设置 cookie

page.deleteCookie(...cookies) 删除指定 cookie

元素选择、操作类

page.$(selector) document.querySelector

page.$$(selector) document.querySelectorAll

page.type(selector, text[, options]) 模拟键盘输入内容

page.click(selector[, options]) 点击匹配元素

page.tap(selector) 点击匹配元素(通过 page.touchscreen 点击)

page.focus(selector) 使匹配元素获得焦点

page.hover(selector) 使匹配元素获得hover状态

page.select(selector, ...values) 选中匹配的选择器,触发change和input事件

waitFor 系列

page.waitForFunction(pageFunction[, options[, ...args]]):等待函数执行完成

page.waitForNavigation([options]):等待页面跳转完成

page.waitForRequest(urlOrPredicate[, options]):等待匹配的请求

page.waitForResponse(urlOrPredicate[, options]):等待匹配的响应

page.waitForSelector(selector[, options]):等待指定的选择器匹配的元素出现在页面中

page.waitForXPath(xpath[, options]):等待指定的xpath匹配的元素出现在页面中

page.waitForTimeout(milliseconds) :等待的毫秒数 (v10.1.0 新增 )

page.waitFor(selectorOrFunctionOrTimeout[, options[, ...args]]) :新版本中已废弃,使用 waitForSelector、waitForFunction、 waitForTimeout 代替

总之很实用类

page.pdf([options]) 生成PDF

page.screenshot([options]) 截图


实战场景

Puppeteer 实战场景 —— 生成 PDF


参考链接

文档类

Puppeteer 官网:https://pptr.dev

Puppeteer 中文文档:https://learnku.com/docs/puppeteer/3.1.0

Puppeteer 中文文档(另一版):http://www.puppeteerjs.com/


经验帖

puppeteer (Nodejs版selenium )快速入门

puppetee 常用API

Puppeteer如何从多个HTMLS生成PDF

puppeteer 生成pdf,绝对解决你的需求