关于Puppeteer的那些事儿
最近开始上手一个自动化测试工具Puppeteer,来谈一谈关于它的一些事儿。
Puppeteer中文文档:https://zhaoqize.github.io/puppeteer-api-zh_CN/#?product=Puppeteer&version=v1.20.0&show=api-class-puppeteer(推荐看完预热视频后再读API)
Puppeteer官方文档:https://github.com/GoogleChrome/puppeteer
预热视频:https://www.youtube.com/watch?v=IvaJ5n5xFqU 以及 https://www.youtube.com/watch?v=ARt3zDHSsd4
在线编写测试网站:https://try-puppeteer.appspot.com/
puppeteer社区:https://slack.com/
√安装
安装puppeteer
- cnpm i puppeteer
安装puppeteer-core
- cnpm i puppeteer-core
√常用方法或属性:
1. puppeteer.launch([options])
- //Puppeteer 模块提供了一种启动 Chromium 实例的方法。 下面就是使用 Puppeteer 进行自动化的一个典型示例:
- const puppeteer = require('puppeteer');
- puppeteer.launch().then(async browser => {
- const page = await browser.newPage();
- await page.goto('https://www.google.com');
- // 其他操作...
- await browser.close();
- });
2.Browser
当 Puppeteer 连接到一个 Chromium 实例的时候会通过 puppeteer.launch 或 puppeteer.connect 创建一个 Browser 对象。
- //下面是使用 Browser 创建 Page 的例子
- 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 的例子:
- 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();
- });
3.Page
Page 提供操作一个 tab 页或者 extension background page 的方法。一个 Browser 实例可以有多个 Page 实例。
下面的例子创建一个 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();
- });
4.Keyboard
Keyboard 提供一个接口来管理虚拟键盘. 高级接口为 keyboard.type, 其接收原始字符, 然后在你的页面上生成对应的 keydown, keypress/input, 和 keyup 事件.
为了更精细的控制(虚拟键盘), 你可以使用 keyboard.down, keyboard.up 和 keyboard.sendCharacter 来手动触发事件, 就好像这些事件是由真实的键盘生成的.
- //持续按下 Shift 来选择一些字符串并且删除的例子:
- await page.keyboard.type('Hello World!');
- await page.keyboard.press('ArrowLeft');
- await page.keyboard.down('Shift');
- for (let i = 0; i < ' World'.length; i++)
- await page.keyboard.press('ArrowLeft');
- await page.keyboard.up('Shift');
- await page.keyboard.press('Backspace');
- // 结果字符串最终为 'Hello!'
- //按下A的例子
- await page.keyboard.down('Shift');
- await page.keyboard.press('KeyA');
- await page.keyboard.up('Shift');
5. Mouse
Mouse 类在相对于视口左上角的主框架 CSS 像素中运行。
每个 page 对象都有它自己的 Mouse 对象,使用见 page.mouse。
- // 使用 ‘page.mouse’ 追踪 100x100 的矩形。
- await page.mouse.move(0, 0);
- await page.mouse.down();
- await page.mouse.move(0, 100);
- await page.mouse.move(100, 100);
- await page.mouse.move(100, 0);
- await page.mouse.move(0, 0);
- await page.mouse.up();
更多方法和属性请阅读官网
√实战01:跳转指定页面
源码:跳转到百度首页
- const puppeteer=require('puppeteer');
- (async ()=>{
- const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800}});
- const page= await browser.newPage();
- await page.goto("https://www.baidu.com");
- })();
效果:
√实战02:输入文本与元素点击
代码:在百度中搜索
- const puppeteer=require('puppeteer');
- (async ()=>{
- const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800}});
- const page= await browser.newPage();
- await page.goto("https://www.baidu.com"); //跳转页面
- const input_text= await page.$("#kw"); //获取百度首页的搜索框。page.$()用来查找元素
- await input_text.type("Hello Word!"); //type()输入内容
- const btn_click=await page.$("#su"); //获取百度首页的搜索按钮。
- await btn_click.click(); //点击搜索按钮。
- })();
效果:
√实战03:获取文本元素值
源码:获取百度词条的值
- const puppeteer=require('puppeteer');
- (async ()=>{
- const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800}});
- const page= await browser.newPage();
- await page.goto("https://www.baidu.com"); //跳转页面
- const input_text= await page.$("#kw"); //获取百度首页的搜索框。page.$()用来查找元素
- await input_text.type("Hello Word!"); //type()输入内容
- const btn_click=await page.$("#su"); //获取百度首页的搜索按钮。
- await btn_click.click(); //点击搜索按钮。
- await page.waitFor('div#content_left > .result-op.c-container.xpath-log',{visible:true});//由于获取元素是异步操作,需要等待该元素加载出来
- let resultText= await page.$eval('div#content_left > .result-op.c-container.xpath-log',ele=>{return ele.innerHTML})//获取元素并返回元素下的innerHTML。 .$eval表示获取单个元素
- console.log("result is ",resultText);//在控制台打印出值。
- })();
演示:
√实战04:puppeteer文件上传操作
代码:在百度首页上传图片
- const puppeteer=require('puppeteer');
- (async ()=>{
- const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800}});
- const page = await browser.newPage();
- await page.goto('https://www.baidu.com');
- await page.waitForSelector('span.soutu-btn'); //等待选择元素出现
- const soutuBtn=await page.$('span.soutu-btn'); //获取图片按钮
- await soutuBtn.click(); //点击展开图片按钮
- await page.waitForSelector('input.upload-pic'); //等待上传按钮出现
- const uploadPic=await page.$('input.upload-pic'); //获取上传按钮
- await uploadPic.uploadFile('C:\\Capture.PNG'); //上传图片。注意:路径要用双斜杠。
- })();
演示:
√实战05:puppeteer处理多个元素
代码:打印京东上的手机信息
- const puppeteer = require('puppeteer');
- (async()=>{
- const browser=await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800}});
- const page =await browser.newPage();
- await page.goto('https://www.jd.com');
- await page.waitFor("#key");
- const inputText=await page.$("#key");
- await inputText.type("手机");
- await page.keyboard.press('Enter');
- await page.waitForSelector("ul.gl-warp > li");
- const items=await page.$$eval("ul.gl-warp > li",eles=>eles.map(ele=>ele.innerText));
- console.log("手机列表=",items);
- })();
演示:
√实战06:puppeteer切换iframe进行操作
iframe跟page的用法类似。使用前需要切换到iframe里面并用src定位要操作的iframe。操作可参考:https://github.com/GoogleChrome/puppeteer/blob/v1.20.0/docs/api.md#class-frame
代码:自动在阿里云的注册iframe里面填写注册信息
- const puppeteer = require('puppeteer');
- (async()=>{
- const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800}});
- const page = await browser.newPage();
- await page.goto("https://account.aliyun.com/register/register.html");
- //切换iframe
- const frame= await page.frames().find(frame=>frame.url().includes("https://passport.aliyun.com"));//切换iframe,并找到对应src的iframe
- await frame.waitFor("input#nick"); //等待输入框加载完成
- const nick =await frame.$("input#nick");//获取输入框
- await nick.type("测试用户");//输入数据
- })();
演示:
√实战07:puppeteer拖拽操作阿里云验证码
代码:自动操作阿里云验证滑动模块
- const puppeteer = require('puppeteer');
- (async()=>{
- const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1000,height:800},ignoreDefaultArgs:["--enable-automation"]});//在有些页面可能需要将automation提示去掉。使用ignoreDefaultArgs:["--enable-automation"]参数
- const page = await browser.newPage();
- await page.goto("https://account.aliyun.com/register/register.html");
- //切换iframe
- const frame= await page.frames().find(frame=>frame.url().includes("https://passport.aliyun.com"));//切换iframe,并找到对应src的iframe
- await frame.waitForSelector("span#nc_1_n1z");//等待滑动块加载完成
- const span =await frame.$("span#nc_1_n1z"); //获取滑动元素
- const spanInfo=await span.boundingBox(); //获取滑动块的信息,包括位置(x,y)以及宽和高
- //console.log(spanInfo);
- await frame.waitForSelector("div#nc_1_n1t"); //等待包裹滑块的div加载完成
- const outDiv=await frame.$("div#nc_1_n1t"); //获取包裹滑块的div
- const outDivInfo=await outDiv.boundingBox(); //获取包裹滑块的div的信息,包括位置(x,y)以及宽和高
- //console.log(outDivInfo);
- await page.mouse.move(spanInfo.x,spanInfo.y);//将鼠标移动到滑块位置
- await page.mouse.down(); //将鼠标按下(默认是左键)
- for(var i=0;i<outDivInfo.width;i++){
- page.mouse.move(spanInfo.x+i,spanInfo.y);//让鼠标向左移动outDivInfo的宽度距离
- }
- await page.mouse.up(); //将鼠标松开
- })();
演示:
√实战08:puppeteer自动抓取百度新闻上的语句并自动登录微博账户发一条微博
代码:这个实战似乎翻车了,被微博检测到自动化而被要求输入验证码
- const puppeteer = require('puppeteer');
- const config=require('./config'); //为了保护我的个人隐私,所以我把账号和密码保存在了config文件中
- (async ()=>{
- // console.log(config.username);
- // console.log(config.password);
- const browser = await puppeteer.launch({
- headless:false,
- defaultViewport:{width:1280,height:800},
- ignoreDefaultArgs:["--enable-automation"],//移除自动化,防止页面生成验证码
- slowMo:200,//输入延迟时间
- args:['--window-size:1280,800'],//调整窗口大小
- });
- const page= await browser.newPage();
- await page.goto('https://news.baidu.com/',{waitUntil:"networkidle2"});//第一个参数是要前往的地址url,第二个参数是保证页面全部加载
- await page.waitForSelector('#imgTitle>a>strong');
- const newsText=await page.$eval("#imgTitle>a>strong",ele=>ele.innerText);//匹配第一个元素
- // console.log(newsText);
- await page.goto('https://weibo.com',{waitUntil:"networkidle2"});
- await page.waitFor(5*1000);//防止被检测
- await page.reload();//防止被检测
- await page.waitForSelector('#loginname'); //等待账号输入框加载完成
- const inputText=await page.$('#loginname'); //获取账号输入框元素
- await inputText.click(); //防止被检测,具体情况具体分析
- await inputText.type(config.username);
- await page.waitForSelector('input[name="password"]'); //等待密码输入框加载完成
- const inputPwd=await page.$('input[name="password"]'); //获取密码输入框
- await inputPwd.click();//防止被检测,具体情况具体分析
- await inputPwd.type(config.password);
- await page.waitForSelector('a[action-type="btn_submit"]'); //等待确认按钮加载
- const submit=await page.$('a[action-type="btn_submit"]'); //获取确认按钮
- await submit.click(); //点击
- })();
演示:翻车啦!!!
√实战09:puppeteer模拟快捷键
代码演示:https://github.com/GoogleChrome/puppeteer/blob/v1.20.0/docs/api.md#class-keyboard
√实战10:puppeteer切换浏览器tab页
主要用到api:browser.target();
文档:https://github.com/GoogleChrome/puppeteer/blob/v1.20.0/docs/api.md#class-browser
√实战11:puppeteer处理弹出的对话框
主要用到的api:Dialog处理弹出的内容
文档:https://github.com/GoogleChrome/puppeteer/blob/v1.20.0/docs/api.md#class-dialog
√实战12:puppeteer执行JavaScript方法
主要用到的方法:page.evaluate(()=>{ 在这里面可以写任意JS代码 })
文档:https://github.com/GoogleChrome/puppeteer/blob/v1.20.0/docs/api.md#class-page
√实战13:配置typescript环境,并在其中使用puppeteer
待完善
√实战14:获取全屏截图
源码:
- const puppeteer =require('puppeteer');//引入puppeteer
- (async()=>{//使用自执行函数
- const browser = await puppeteer.launch();//生成browser实例
- const page = await browser.newPage();//生成一个页面
- await page.goto('https://cn.aliyun.com/');//前往页面
- console.log(await page.content());//打印页面信息(源码)
- await page.screenshot({//截图
- path: 'ali.png',
- fullPage: true
- });
- await browser.close();//关闭browser实例
- })();
效果图:
关于Puppeteer的那些事儿的更多相关文章
- 说说Makefile那些事儿
说说Makefile那些事儿 |扬说|透过现象看本质 工作至今,一直对Makefile半知半解.突然某天幡然醒悟,觉得此举极为不妥,只得洗心革面从头学来,以前许多不明觉厉之处顿时茅塞顿开,想想好记性不 ...
- 总结iOS开发中的断点续传那些事儿
前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...
- setTimeout那些事儿
一.setTimeout那些事儿之单线程 一直以来,大家都在说Javascript是单线程,浏览器无论在什么时候,都且只有一个线程在运行JavaScript程序. 但是,不知道大家有疑问没——就是我们 ...
- Javascript中关于cookie的那些事儿
Javascript-cookie 什么是cookie? 指某些网站为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据(通常经过加密).简单点来说就是:浏览器缓存. cookie由什 ...
- webpack那些事儿
webpack那些事儿01-webpack到底是什么 webpack那些事儿02-从零开始 webpack那些事儿03-热插拔 hot webpack那些事儿04-spa项目实战分析 webpack那 ...
- 关于JSON的那些事儿
JSON的那些事儿 曾经有一段时间,XML是互联网上传输结构化数据的事实标准,其突出特点是服务器与服务器间的通信.但是业内不少人认为XML过于繁琐.冗长,后面为了解决这个问题也出现了一些方案,但是由于 ...
- MVC之前的那点事儿系列(10):MVC为什么不再需要注册通配符(*.*)了?
文章内容 很多教程里都提到了,在部署MVC程序的时候要配置通配符映射(或者是*.mvc)到aspnet_ISPAI.dll上,在.NET4.0之前确实应该这么多,但是.NET4.0之后已经不要再费事了 ...
- MVC之前的那点事儿系列(8):UrlRouting的理解
文章内容 根据对Http Runtime和Http Pipeline的分析,我们知道一个ASP.NET应用程序可以有多个HttpModuel,但是只能有一个HttpHandler,并且通过这个Http ...
- CSS知识回顾--读《CSS 那些事儿》笔记
由于之前有了解过CSS的相关知识,有了一定的基础,所以读起<CSS 那些事儿>不是很有难度,况且我现在读起来时,CSS3和HTML5比较流行,这里只是记录一些CSS知识记录,不做详细铺开, ...
随机推荐
- CTU Open 2018 Lighting /// 组合数递推 二进制
题目大意: 给定n k 给定一个数的二进制位a[] 求这个数加上 另一个二进制位<=n的数b 后 能得到多少个不同的 二进制位有k个1 的数 样例 input10 51000100111 out ...
- java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation getting while running test project?
转摘:http://stackoverflow.com/questions/11155340/java-lang-illegalaccesserror-class-ref-in-pre-verifie ...
- IT面试技巧(2)
21.最能概括你自己的三个词是什么? 回答提示:我经常用的三个词是:适应能力强,有责任心和做事有始终,结合具体例子向主考官解释, 22.你的业余爱好是什么? 回答提示:找一些富于团体合作精神的,这里有 ...
- HTML 使用CSS 如何去掉文本聚焦框 HTML 使用CSS 如何去掉文本聚焦框 : outline 值设为none 修改input、textarea输入框placeholder样式
HTML 使用CSS 如何去掉文本聚焦框 : outline 值设为none 修改input.textarea输入框placeholder样式 兼容性代码: input::-webkit-input ...
- 基于mybatis拦截器分表实现
1.拦截器简介 MyBatis提供了一种插件(plugin)的功能,但其实这是拦截器功能.基于这个拦截器我们可以选择在这些被拦截的方法执行前后加上某些逻辑或者在执行这些被拦截的方法时执行自己的逻辑. ...
- Java高频经典面试题(第一季)五:递归与迭代
编程题: 有n步台阶, 一次只能上 1步 或 2步, 共有多少种走法? 递归 循环迭代 递归: package will01; import org.junit.Test; public class ...
- 启动ABP项目
1.在官网下载ABP项目 2.打开项目选择解决方案,右击还原NuGet包 3.修改appsettings.json中的ConnectionStrings 例子"ConnectionStrin ...
- 百度地图,删除marker,创建marker
-------------------[删除marker]-----------------------------success: function(data){ if(data.length> ...
- jq实现跟随鼠标点击移动的下划线效果
效果如下: 1.html代码: <div class="center-left-tap"> <a href="javascript:void (0)&q ...
- 【Tomcat】1.Tomcat在Windows系统的安装和使用
1.下载与安装 安装Tomcat的[前提条件]是安装好JDK或者JRE(本文略过)Tomcat在Windows系统中可以通过[压缩包]或[安装包]来安装建议使用[安装包]来简化安装步骤登录官网http ...