Puppeteer基础入门、常见应用、利用谷歌插件编写Puppeteer脚本

前言

Puppeteer已经听说过很多次了,也见过一些与之相关的文章。但是一直没怎么研究过,现在来简单学习一下。

简介

Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。Puppeteer 默认以 headless 模式运行,但是可以通过修改配置文件运行“有头”模式。

功能

  • 生成页面 PDF。
  • 抓取 SPA(单页应用)并生成预渲染内容(即“SSR”(服务器端渲染))。
  • 自动提交表单,进行 UI 测试,键盘输入等。
  • 创建一个时时更新的自动化测试环境。 使用最新的 JavaScript 和浏览器功能直接在最新版本的Chrome中执行测试。
  • 捕获网站的 timeline trace,用来帮助分析性能问题。
  • 测试浏览器扩展。

官方文档: https://puppeteer.bootcss.com/

推荐文章: 奶奶都能轻松入门的 Puppeteer 教程

准备

安装

npm i puppeteer

安装时会下载最新版的Chromium,以保证可以使用 API。

注: 默认下载时会下载最新版本,如果你的node版本过低会出现下面这个问题,要么升级node版本,要么下载旧版本的Puppeteer。我这里更新了一下node的版本

在这里插入图片描述
在这里插入图片描述

除了上面那个问题,如果你还遇到了类似ERROR: Failed to set up Chrome r116.0.5845.96! Set "PUPPETEER_SKIP_DOWNLOAD" env variable to skip download 这样的问题,这是因为 当你安装 Puppeteer 时,它会下载最新版本的Chromium(~170MB Mac,~282MB Linux,~280MB Win),以保证可以使用 API。
这说明下载Chromium失败了,我这里最终解决这个问题是通过安装低版本的Puppeteer

npm install puppeteer.11.1

执行官方示例,验证是否安装成功

下面我们执行一下官方提供的截图例子:
example.js

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();
})();
node example.js

在这里插入图片描述
出现了以上这个图片,上面你已经安装成功了,下面进入正题

使用

基本使用

const puppeteer = require("puppeteer");// 初始化函数
const init = async () => {// 启动浏览器const browser = await puppeteer.launch({headless: false, // 是否以无头模式运行,默认为 true,除非选择开启了开发者工具devtools: true, // 是否自动打开开发者工具,默认为 falseargs: ["--start-maximized"], // 启动时传递给浏览器的额外参数});// 创建一个标签页const page = await browser.newPage();// 跳转到相应的网站await page.goto("https://example.com");// 截图等其他操作await page.screenshot({ path: "example.png" });// 关闭浏览器await browser.close();
};init();

无头模式和有头模式
无头模式和有头模式是Puppeteer中的两种不同的浏览器运行模式。

  • 无头模式(Headless Mode):无头模式表示在后台运行浏览器,没有可见的用户界面。它在无需图形界面的场景下非常有用,比如进行自动化测试、爬取网页数据等。无头模式的优势是节省资源,提高性能,因为它不需要渲染和显示页面。

  • 有头模式(Headful Mode):有头模式表示以常规的图形界面方式运行浏览器,可以看到实际的浏览器页面。这对于调试和开发过程中的可视化操作非常有帮助,比如查看页面布局、调试JavaScript等。有头模式通常会消耗更多的系统资源,因为它需要进行页面渲染和显示。

有头模式运行时如下,会出现一个图形界面,操作执行完成后会自动关闭
在这里插入图片描述
puppeteer.launch的其他常用配置属性

//  <boolean> 是否在导航期间忽略 HTTPS 错误. 默认是 false。
// 当设置为true时,Puppeteer在导航过程中会忽略与 HTTPS 相关的错误,例如证书错误或安全警告。这在某些情况下很有用,例如当你访问的网站的 SSL 证书有问题或者过期时,仍然可以继续进行导航和操作。
// 忽略 HTTPS 错误的情况下,你的连接可能是不安全的。因此,在生产环境中,建议不要使用这个选项
ignoreHTTPSErrors// <?Object> 为每个页面设置一个默认视口大小。包括宽高、缩放的,默认为800 * 600
defaultViewport // <Array<string>> 传递给浏览器实例的其他参数。具体见官方文档
args 

错误处理

const {TimeoutError} = require('puppeteer/Errors');try {// 等待获取dom元素await page.waitForSelector('.foo');
} catch (e) {if (e instanceof TimeoutError) {// 如果超时,做一些处理。}
}

page

Page 提供操作一个 tab 页或者 extension background page 的方法。一个 Browser 实例可以有多个 Page 实例。

在实际应用中,几乎所有常见的应用都是围绕着页面来使用的。如果想要玩好Puppeteer 就需要掌握好Page

事件

我们可以通过page.on 或者 page.once 来监听事件,通过page.removeListener来移除事件

function logRequest(interceptedRequest) {console.log('A request was made:', interceptedRequest.url());
}
page.on('request', logRequest);
// 一段时间后...
page.removeListener('request', logRequest);

常见的事件

  • close:当页面关闭时触发
  • domcontentloaded:当页面的 DOMContentLoaded(当 HTML 文档被完全解析,并且所有延迟脚本都已下载并执行时,将触发 DOMContentLoaded 事件。它不会等待图像、子帧和异步脚本等其他内容完成加载。)事件被触发时触发。
  • error:当页面崩溃是触发
  • load:当页面的 load 事件被触发时触发
  • request:当页面发送一个请求时触发。参数 request 对象是只读的。 如果需要拦截并且改变请求,参考 page.setRequestInterception
  • requestfailed:当页面的请求失败时触发。比如某个请求超时了
  • requestfinished:当页面的某个请求成功完成时触发。
  • response:当页面的某个请求接收到对应的 response 时触发

常用方法

  • page.$(selector) :此方法在页面内执行 document.querySelector。如果没有元素匹配指定选择器,返回值是 null。
  • page.$$(selector):此方法在页面内执行 document.querySelectorAll。如果没有元素匹配指定选择器,返回值是 []。
  • page.$eval(selector, pageFunction[, ...args]):此方法在页面内执行 document.querySelector,然后把匹配到的元素作为第一个参数传给 pageFunction。如果 pageFunction 返回的是 Promise,那么此方法会等 promise 完成后返回其返回值。const searchValue = await page.$eval('#search', el => el.value); 类似于找到这个dom元素,并对这个dom元素执行一些操作。
  • page.$$eval(selector, pageFunction[, ...args]):此方法在页面内执行 Array.from(document.querySelectorAll(selector)),然后把匹配到的元素数组作为第一个参数传给 pageFunction。如果 pageFunction 返回的是 Promise,那么此方法会等 promise 完成后返回其返回值。
  • page.addScriptTag(options):往页面中注入脚本,await page.addScriptTag({ path: 'path/to/your/script.js' }); 跟浏览器插件中的脚本注入基本上是一样的,通过注入的脚本来修改页面
  • page.addStyleTag(options):往页面中注入样式,await page.addStyleTag({ path: 'path/to/your/styles.css' });
  • page.browser():得到当前 page 实例所属的 browser 实例。
  • page.click(selector[, options]):点击指定的元素,如果有多个匹配的原生,点击第一个
  • page.content():返回完整的html代码
  • page.focus(selector):使指定元素获取焦点,如果有多个匹配的元素,焦点给第一个元素
  • page.goBack([options]):导航到页面历史的前一个页面
  • page.goForward([options]):导航到页面历史的后一个页面
  • page.goto(url[, options]):跳转到指定url的网页
  • page.isClosed():判断页面是否被关闭
  • page.evaluate(pageFunction[, ...args]):在页面实例上下文中执行方法,返回方法执行的结果
  • page.keyboard:用于与键盘进行交互的类
  • page.mouse:用于与鼠标进行交互的类
  • page.pdf([options]):生成当前页面的pdf文件,默认会返回一个二进制编码,具体配置见文档
  • page.screenshot([options]):生成页面截图,默认会返回一个二进制编码,也可以设置为base64,具体配置见文档
  • page.select(selector, ...values):用于选择页面中的下拉列表。它接受一个选择器参数和一个或多个值参数。该方法会在页面上找到匹配选择器的下拉列表元素,并将值参数中的选项选中。例如:`await page.select(‘select#myDropdown’, ‘option1’, ‘option2’);
  • page.setExtraHTTPHeaders(headers):当前页面发起的每个请求都会带上这些请求头
  • page.setRequestInterception(value):是否启用请求拦截器,启用请求拦截器,会激活 request.abort,request.continuerequest.respond 方法。这提供了修改页面发出的网络请求的功能。一旦启用请求拦截,每个请求都将停止,除非它继续,响应或中止
  • page.title():返回页面标题
  • page.type(selector, text[, options]):用于输入内容,例如
page.type('#mytextarea', 'Hello'); // 立即输入
page.type('#mytextarea', 'World', {delay: 100}); // 输入变慢,像一个用户
  • page.waitForNavigation([options]):用于等待页面导航完成,只有当新页面加载完成后才可以继续进行后续操作。
  • page.waitForSelector(selector[, options]):等待指定的选择器匹配的元素出现在页面中,如果调用此方法时已经有匹配的元素,那么此方法立即返回。 如果指定的选择器在超时时间后扔不出现,此方法会报错。

Keyboard

Keyboard 提供一个接口来管理虚拟键盘. 高级接口为 keyboard.type,,其接收原始字符, 然后在你的页面上生成对应的 keydownkeypress/inputkeyup 事件

常用方法

page.type:接收字符

page.type('#mytextarea', 'Hello'); // 立即输入
page.type('#mytextarea', 'World', {delay: 100}); // 输入变慢,像一个用户

keyboard.down(key[, options]):按下指定键

await page.keyboard.down('Shift');

keyboard.up(key):释放按下的键

await page.keyboard.up('Shift');

使用keyboard.down按下的键必须使用keyboard.up进行释放,否则该键会一直保持按下的状态

keyboard.press(key[, options]):按下并里面释放该键,相当于keyboard.downkeyboard.up的组合,可以指定按下与释放之间的间隔时间

await page.keyboard.press('KeyA');

Mouse

Mouse用于模拟鼠标

常用方法

mouse.click(x, y, [options]):使用鼠标点击指定位置,默认左键,点击一次

mouse.down([options]) :鼠标按下,默认是左键,默认按下一次

mouse.up([options]):鼠标抬起,默认左键,默认一次

示例

做一个稍微复杂一点的例子:

步骤
1、打开菜鸟教程的主界面
在这里插入图片描述
2、点击 学习HTML5这个标签,进入对应的页面
在这里插入图片描述
3、点击 HTML图像,进入对应的页面
在这里插入图片描述
4、将这个图片下载到本地

代码

const puppeteer = require("puppeteer");// 初始化函数
const init = async () => {// 启动浏览器const browser = await puppeteer.launch({headless: false,});// 创建一个标签页const page = await browser.newPage();// 跳转到相应的网站await page.goto("https://www.runoob.com/");// 元素是动态生成的,需要等待元素完全加载await page.waitForSelector(".item-top.item-1");// 获取到 学习html5对应的标签const html5 = await page.$$(".item-top.item-1");// 返回值是CDPElementHandle { handle: CDPJSHandle {} },一个CDP元素句柄,指向浏览器中实际dom元素的引用// 需要使用 evaluate方法来获取对应的dom中的属性,比如元素的innerText属性是在浏览器环境中计算得出的,而不是直接在 Puppeteer 中可见的console.log("html5[1]:", html5[1]);// 点击该标签await html5[1].click();// 等待页面渲染出现a标签的元素await page.waitForSelector("a");// 获取HTML 图像并点击const htmlImg = await page.$('a[title="HTML 图像"]');console.log("htmlImg:", htmlImg);htmlImg.click();await page.waitForSelector(".example_result.notranslate img");// 获取到图片标签const img = await page.$(".example_result.notranslate img");const imageSrc = await img.evaluate((el) => el.src);console.log("图片地址:", imageSrc);// 图片截图await img.screenshot({ path: "example.png" });// 关闭浏览器await browser.close();
};init();

效果图
在这里插入图片描述

注意点:

  • 为了方便开发,最好设置为headless: false,另外不要关闭浏览器,这样方便查看具体效果,看一下是否有问题。当确认代码没问题后在设置为headless: true,并在最后关闭浏览器
  • page.$(".example_result.notranslate img") 获取到的是一个CDPElementHandle { handle: CDPJSHandle {} } 。这是一个CDP元素句柄,指向浏览器中实际dom元素的引用。你可以直接调用click等方法,但是无法直接获取到比如元素的innerText属性。查到的解释是元素的innerText属性是在浏览器环境中计算得出的,而不是直接在 Puppeteer 中可见的,可以通过evaluate方法来操纵上下文对象
  • page.waitForSelector("a") ,等待某个元素渲染出,因为是代码直接操作,可能会出现页面还没有渲染完成就开始执行下一步,导致代码报错
  • img.evaluate((el) => el.src) 执行上下文对象

利用谷歌插件编写Puppeteer脚本

什么,你不会写脚本?什么,你觉得写脚本麻烦?什么,可以让插件写脚本?

没错,你不会写脚本也没关系,可以使用谷歌插件让插件帮你写脚本。这里我们需要使用Headless Recorde

简介
Headless Recorder 是一个 Chrome 浏览器插件,它可以帮助你录制和回放你在浏览器中的操作。它的主要功能是将你在浏览器中的操作记录下来,并生成可重放的代码,以便你可以在任何时间重新执行这些操作。

Headless Recorder 是一个非常实用的工具,特别适用于自动化测试、网页演示和教学等场景。使用它可以快速生成可重放的代码,无需手动编写和调试脚本,节省了大量的开发和测试时间。

Headless Recorder 的工作原理是利用 Chrome 浏览器的 Headless 模式,它可以在后台运行浏览器并模拟用户的操作,包括点击、输入、滚动等等。通过插件的录制功能,你可以在浏览器中进行各种操作,同时插件会将这些操作记录下来,并生成对应的代码。

录制完成后,你可以将生成的代码导出为多种格式,如 JavaScript、Puppeteer、Playwright 等,以便在其他环境中运行和重放。这样你就可以在不同的环境中复现你在浏览器中的操作,而无需手动重复操作。

总之,Headless Recorder 是一个强大的工具,它可以帮助你快速记录和回放浏览器中的操作,提高开发效率和测试质量。无论是自动化测试还是网页演示,它都是一个非常有用的辅助工具。

官方地址
https://github.com/checkly/headless-recorder

基本操作
开启Headless Recorde插件后,Headless Recorde会录制你在浏览器中的操作,当结束录制后。会将你在浏览器中的操作转换为脚本,比如:
在这里插入图片描述
下面是生成的代码(需要稍微修改一下)

const init = async () => {const puppeteer = require("puppeteer");const browser = await puppeteer.launch();const page = await browser.newPage();const navigationPromise = page.waitForNavigation();await page.goto("https://www.runoob.com/");await page.setViewport({ width: 1920, height: 969 });await page.waitForSelector(".row > .col > .cate1 > .item-top:nth-child(3) > h4");await page.click(".row > .col > .cate1 > .item-top:nth-child(3) > h4");await navigationPromise;await page.waitForSelector(".runoob-col-md2 > .left-column > .sidebar-box > #leftcolumn > a:nth-child(13)");await page.click(".runoob-col-md2 > .left-column > .sidebar-box > #leftcolumn > a:nth-child(13)");await navigationPromise;await page.waitForSelector(".article-body > #content > .example > .example_result > img");await page.click(".article-body > #content > .example > .example_result > img");const element1 = await page.$(".article-body > #content > .example > .example_result > img");await element1.screenshot({ path: "screenshot_1.png" });await browser.close();
};init();

一对比,比自己写的脚本不知道牛逼了多少倍。

下载
下载谷歌商店里好像下架了该插件,你可以直接百度搜索,当然也可以下载我下载好了的插件,插件已经上传的百度云盘

链接:https://pan.baidu.com/s/1k8fvl-CemYOMUedsZmjBnQ
提取码:1234

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/138003.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【离网逆变器】离网逆变器型号由一个高频DC-DC升压转换器与全桥PI控制电压源逆变器级联组成、逆变器使用带LC滤波器的SPWM调制(Simulink)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

HTML5+CSS3+JS小实例:鼠标控制飞机的飞行方向

实例:鼠标控制飞机的飞行方向 技术栈:HTML+CSS+JS 效果: 源码: 【html】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" conten…

Vue项目前端代码防止被调试

项目背景 被安全测试针对了&#xff0c;总是调试我这不太安全的代码。前端代码深度混淆转成十六进制还不行&#xff0c;仍然找到加密方法&#xff0c;对后端数据进行解密。这次就修改了思路换种方法: 我承认阁下很强&#xff0c;但假如, 我是说假如打开控制台是空白页面&…

森林防火可视化智能监管与风险预警系统解决方案

一、方案背景 森林火灾是世界八大自然灾害之一&#xff0c;具有发生面广、突发性强、破坏性大、危险性高、处置扑救特别困难等特点&#xff0c;严重危及人民生命财产和森林资源安全&#xff0c;甚至引发生态灾难。有效预防和及时控制森林火灾是保护国家生态建设成果、推进生态…

eclipse svn插件安装

1.进入eclipse的help->Eclipse Marketplace,如下图所示&#xff1a; 2.输入“svn”,再按回车&#xff0c;如下图&#xff1a; 3.这我选择的是 Subversive,点击后面的“install”按钮&#xff0c;如下图 Eclipse 下连接 SVN 库有两种插件 —— Subclipse 与 Subversive &…

【MySQL基础】--- 约束

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【MySQL学习专栏】&#x1f388; 本专栏旨在分享学习MySQL的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 目录 一、什么…

linux离线安装make

一、下载rpm包 https://pkgs.org/search/?qmake 二、拷贝至服务器 三、安装make rpm -ivh make-3.82-24.el7.x86_64.rpm四、查看是否安装成功 make -v

Docker部署单点Elasticsearch与Kibana

一 、 创建网络 因为需要部署kibana容器&#xff0c;因此需要让es和kibana容器互联。这里创建一个网络&#xff1a; docker network create es-net # 创建一个网络名称为:es-net 二 、拉取并加载镜像 方式一 docker pull elasticsearch:7.12.1 版本为elasticsearch的7…

【面试题】Js数组去重都有哪些方法?

前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 表妹一键制作自己的五星红旗国庆头像&#xff0c;超好看 1. indexOf 定义&#xff1a; indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置…

60从零开始学Java之与数字相关的类有哪些?

作者&#xff1a;孙玉昌&#xff0c;昵称【一一哥】&#xff0c;另外【壹壹哥】也是我哦 千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者 前言 我们在解决实际问题时&#xff0c;会经常对数字、日期和系统设置进行处理&#xff0c;比如在我们的代…

期权如何交易?期权如何做模拟交易?

买卖期权的第一步就是要有期权账户&#xff0c;国内的期权品种有商品期权和ETF期权以及股指期权&#xff0c;每种的开户方式和要求都不同&#xff0c;下文为大家介绍期权如何交易&#xff1f;期权如何做模拟交易&#xff1f; 一、期权交易需要开立一个期权账户&#xff0c;可以…

Linux shell编程学习笔记1:关于shell的前世今生

一、什么是Shell&#xff1f; Shell英文单词的原意是“外壳”&#xff0c;在计算机领域专指在操作系统&#xff08;Operating System&#xff09;外层&#xff0c;提供用户界面&#xff08;User Interface&#xff09;的程序&#xff0c;主要负责将用户的命令&#xff08;Comma…

微信小程序与idea后端如何进行数据交互

交互使用的其实就是调用的req.get(url)方法 进行路径访问&#xff0c;你要先保证自己的springboot项目已经成功运行了&#xff1a; 如下&#xff1a; 如何交互的&#xff1f; 微信小程序&#xff1a;如下为index.js页面 在onLoad()事件中调用方法Project.findAllCities() 要…

flex弹性盒模型与阿里图标的使用

华子目录 flex布局flex布局原理flex使用三要素 阿里图标&#xff08;字体&#xff09; flex布局 相关学习网站&#xff1a;http://c.biancheng.net/css3/flex.html 1.flex是当前最主流的布局方式&#xff1a;用它布局起来更方便&#xff0c;取代了浮动的作用。 2.浮动布局有缺…

仪表基础知识培训

压力传感器:E+H PMX5x/FMX5x 一、安装:安装注意事项: 1、水平安装时仪表的呼吸孔(1)需要向下安装,并远离污染物。 2、请勿用坚硬的物体擦拭或接触膜片。 3、请勿安装在水泵的入口和搅拌叶附近 二、供电、接线、信号、:二线制,仪表输出4-20mA 三、量程:设置最大最小量程…

Stable Diffusion AI绘图使用记录

1、下载安装使用 官方网站https://github.com/AUTOMATIC1111/stable-diffusion-webui 跟着一步步安装就行&#xff08;英文版的&#xff09; 2、真人转二次元 下载控制插件Contro lnetGitHub - Mikubill/sd-webui-controlnet: WebUI extension for ControlNet 按照官方的安…

基于springboot+vue的便利店信息管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

芯片SoC设计你了解吗?

数字IC设计根据岗位性质一般包含SOC设计&#xff0c;前端设计&#xff0c;ASIC设计&#xff0c;逻辑设计&#xff0c;IP设计&#xff0c;CPU设计等。 有人说&#xff1a;做IP设计就是翻译官&#xff0c;做SOC设计就是连连看。 SoC设计是做什么的&#xff1f;与IP设计有什么不同…

【计算机网络】深入理解TCP协议二(连接管理机制、WAIT_TIME、滑动窗口、流量控制、拥塞控制)

TCP协议 1.连接管理机制2.再谈WAIT_TIME状态2.1理解WAIT_TIME状态2.2解决TIME_WAIT状态引起的bind失败的方法2.3监听套接字listen第二个参数介绍 3.滑动窗口3.1介绍3.2丢包情况分析 4.流量控制5.拥塞控制5.1介绍5.2慢启动 6.捎带应答、延时应答 1.连接管理机制 正常情况下&…

代理IP在各种业务情境中的应用和优势

随着现代互联网的迅速发展&#xff0c;代理IP已成为一种广泛应用于各行业的网络技术。特别是在数据采集、网站建设、安全维护等领域&#xff0c;代理IP的应用越来越受到重视。那么&#xff0c;具体有哪些业务会使用到代理IP呢&#xff1f;我们一起来看一看。 1. 网络爬虫和数据…