使用puppeteer破解极验的滑动验证码


Posted in Javascript onFebruary 24, 2018

基本的流程:

1. 打开前端网,点击登录。

2. 填写账号,密码。

3. 点解验证按钮,通过滑动验证,最后成功登陆。

代码实现:

github上可以checkout。

具体代码如下所示:

run.js

const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPhone = devices['iPhone 6 Plus'];
let timeout = function (delay) {
  return new Promise((resolve, reject) => { 
   setTimeout(() => { 
     try {
      resolve(1)
     } catch (e) {
      reject(0)
     }
   }, delay);
  })
 }
 let page = null
 let btn_position = null
 let times = 0 // 执行重新滑动的次数
 const distanceError = [-10,2,3,5] // 距离误差
 async function run() {
 const browser = await puppeteer.launch({
  headless:false //这里我设置成false主要是为了让大家看到效果,设置为true就不会打开浏览器
 });
 page = await browser.newPage();
 // 1.打开前端网
 await page.emulate(iPhone);
 await page.goto('https://www.qdfuns.com/');
 await timeout(1000);
 // 2.打开登录页面
 page.click('a[data-type=login]')
 await timeout(1000);
 // 3.输入账号密码
 page.type('input[data-type=email]','你的账号')
 await timeout(500);
 page.type('input[placeholder=密码]','你的密码')
 await timeout(1000);
 // 4.点击验证
 page.click('.geetest_radar_tip')
 await timeout(1000);
 btn_position = await getBtnPosition();
 // 5.滑动
 drag(null)
 }
 /**
 * 计算按钮需要滑动的距离 
 * */ 
 async function calculateDistance() {
 const distance = await page.evaluate(() => {
 // 比较像素,找到缺口的大概位置
 function compare(document) {
  const ctx1 = document.querySelector('.geetest_canvas_fullbg'); // 完成图片
  const ctx2 = document.querySelector('.geetest_canvas_bg'); // 带缺口图片
  const pixelDifference = 30; // 像素差
  let res = []; // 保存像素差较大的x坐标
  // 对比像素
  for(let i=57;i<260;i++){
  for(let j=1;j<160;j++) {
   const imgData1 = ctx1.getContext("2d").getImageData(1*i,1*j,1,1)
   const imgData2 = ctx2.getContext("2d").getImageData(1*i,1*j,1,1)
   const data1 = imgData1.data;
   const data2 = imgData2.data;
   const res1=Math.abs(data1[0]-data2[0]);
   const res2=Math.abs(data1[1]-data2[1]);
   const res3=Math.abs(data1[2]-data2[2]);
    if(!(res1 < pixelDifference && res2 < pixelDifference && res3 < pixelDifference)) {
    if(!res.includes(i)) {
     res.push(i);
    }
    } 
  }
  }
  // 返回像素差最大值跟最小值,经过调试最小值往左小7像素,最大值往左54像素
  return {min:res[0]-7,max:res[res.length-1]-54}
 }
 return compare(document)
 })
 return distance;
 }
 /**
 * 计算滑块位置
 */
 async function getBtnPosition() {
 const btn_position = await page.evaluate(() => {
 const {clientWidth,clientHeight} = document.querySelector('.geetest_popup_ghost')
 return {btn_left:clientWidth/2-104,btn_top:clientHeight/2+59}
 })
 return btn_position;
 }
 /**
 * 尝试滑动按钮
 * @param distance 滑动距离
 * */ 
 async function tryValidation(distance) {
 //将距离拆分成两段,模拟正常人的行为
 const distance1 = distance - 10
 const distance2 = 10
 page.mouse.click(btn_position.btn_left,btn_position.btn_top,{delay:2000})
 page.mouse.down(btn_position.btn_left,btn_position.btn_top)
 page.mouse.move(btn_position.btn_left+distance1,btn_position.btn_top,{steps:30})
 await timeout(800);
 page.mouse.move(btn_position.btn_left+distance1+distance2,btn_position.btn_top,{steps:20})
 await timeout(800);
 page.mouse.up()
 await timeout(4000);
 // 判断是否验证成功
 const isSuccess = await page.evaluate(() => {
 return document.querySelector('.geetest_success_radar_tip_content') && document.querySelector('.geetest_success_radar_tip_content').innerHTML
 })
 await timeout(1000);
 // 判断是否需要重新计算距离
 const reDistance = await page.evaluate(() => {
 return document.querySelector('.geetest_result_content') && document.querySelector('.geetest_result_content').innerHTML
 })
 await timeout(1000);
 return {isSuccess:isSuccess==='验证成功',reDistance:reDistance.includes('怪物吃了拼图')}
 }
 /**
 * 拖动滑块
 * @param distance 滑动距离
 * */ 
 async function drag(distance) {
 distance = distance || await calculateDistance();
 const result = await tryValidation(distance.min)
 if(result.isSuccess) {
 await timeout(1000);
 //登录
 console.log('验证成功')
 page.click('#modal-member-login button')
 }else if(result.reDistance) {
 console.log('重新计算滑距离录,重新滑动')
 times = 0
 await drag(null)
 } else {
 if(distanceError[times]){
  times ++
  console.log('重新滑动')
  await drag({min:distance.max,max:distance.max+distanceError[times]})
 } else {
  console.log('滑动失败')
  times = 0
  run()
 }
 }
 }
 run()
package.json
{
 "name": "demo",
 "version": "1.0.0",
 "dependencies": {
 "puppeteer": "^1.0.0"
 }
}

运行

1. 将这个两个文件保存到文件夹下面,终端切换到当前路径下

2. npm i

3. 补上前端网的账号,密码

4. node run

演示

下图演示可以分为四步:

1. 打开登陆页面,输入事先写好的账号密码。

2. 第一次拖动滑块提示“被怪兽吃了”,所以重新计算了新的图片的缺口距离。

3. 第二,三次拖动提示“没正确合拼”,所以重新拖动。

4. 验证成功,登录。

(请将鼠标放到gif上查看演示效果,或者请拖到新窗口打开gif)

使用puppeteer破解极验的滑动验证码 

说明

1. 滑动验证有三个canvas,其中只需要 classname为‘geetest_canvas_fullbg'以及‘geetest_canvas_bg'的进行像素差对比。ps:前者是完整图片,后者是带缺口的图片。

使用puppeteer破解极验的滑动验证码 

2. 每个带缺口的图片都有一块误导的阴影,所以对比像素差的时候,计算出的距离分别是误导阴影以及缺口的。因此,滑动距离的取值,我取‘{min:res[0]-7,max:res[res.length-1]-54}'。当缺口比误导阴影靠左时, min(距离最小值) 值就是滑动距离,否则就是 max(距离最大值)减去滑块宽度 。

使用puppeteer破解极验的滑动验证码 

3. 滑动结果分三种情况:验证成功,被吃了,失败。 “被吃了” 会重新请求图片,所以重新计算了距离再滑动; “失败” 则重新滑动,如果执行 4 次依然失败,则重新run整个流程。

总结

以上所述是小编给大家介绍的使用puppeteer破解极验的滑动验证码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript下4个跨浏览器必备的函数
Mar 07 Javascript
jQuery.parseJSON(json)将JSON字符串转换成js对象
Jul 27 Javascript
JQuery复制DOM节点的方法
Jun 11 Javascript
jQuery表格行上移下移和置顶的实现方法
Oct 08 Javascript
jQuery 跨域访问解决原理案例详解
Jul 09 Javascript
js实现图片淡入淡出切换简易效果
Aug 22 Javascript
BootStrap的select2既可以查询又可以输入的实现代码
Feb 17 Javascript
浅谈JavaScript闭包
Apr 09 Javascript
node实现socket链接与GPRS进行通信的方法
May 20 Javascript
vue-cli3 热更新配置操作
Sep 18 Javascript
游戏开发中如何使用CocosCreator进行音效处理
Apr 14 Javascript
原生Js 实现的简单无缝滚动轮播图的示例代码
May 10 Javascript
Vue的elementUI实现自定义主题方法
Feb 23 #Javascript
elementui的默认样式修改方法
Feb 23 #Javascript
详解plotly.js 绘图库入门使用教程
Feb 23 #Javascript
angular基于ng-alain定义自己的select组件示例
Feb 23 #Javascript
搭建element-ui的Vue前端工程操作实例
Feb 23 #Javascript
使用Vue.js和Element-UI做一个简单登录页面的实例
Feb 23 #Javascript
Vue2 模板template的四种写法总结
Feb 23 #Javascript
You might like
调整优化您的LAMP应用程序的5种简单方法
2011/06/26 PHP
初识通用数据库操作类――前端easyui-datagrid,form(php)
2015/07/31 PHP
使用WordPress发送电子邮件的相关PHP函数用法解析
2015/12/15 PHP
PHP7新特性之抽象语法树(AST)带来的变化详解
2018/07/17 PHP
csdn 论坛技术区平均给分功能
2009/11/07 Javascript
getElementsByTagName vs selectNodes效率 及兼容的selectNodes实现
2010/02/26 Javascript
Javascript事件热键兼容ie|firefox
2010/12/30 Javascript
document.all的一个比较完整的总结及案例
2013/01/31 Javascript
jqGrid日期格式的判断示例代码(开始日期与结束日期)
2013/11/08 Javascript
浅谈jQuery.easyui的datebox格式化时间
2015/06/25 Javascript
js获取鼠标点击的对象,点击另一个按钮删除该对象的实现代码
2016/05/13 Javascript
原生js封装二级城市下拉列表的实现代码
2016/06/16 Javascript
微信小程序中单位rpx和rem的使用
2016/12/06 Javascript
使用微信内嵌H5网页解决JS倒计时失效问题
2017/01/13 Javascript
jquery 仿锚点跳转到页面指定位置的实例
2017/02/14 Javascript
JS排序之选择排序详解
2017/04/08 Javascript
详解封装基础的angular4的request请求方法
2018/06/05 Javascript
JS实现水平遍历和嵌套递归操作示例
2019/08/15 Javascript
Python的面向对象编程方式学习笔记
2016/07/12 Python
Django ORM框架的定时任务如何使用详解
2017/10/19 Python
Python生成MD5值的两种方法实例分析
2019/04/26 Python
python中的数据结构比较
2019/05/13 Python
解决导入django_filters不成功问题No module named 'django_filter'
2020/07/15 Python
Windows下Sqlmap环境安装教程详解
2020/08/04 Python
python批量修改交换机密码的示例
2020/09/22 Python
Raffaello Network西班牙:意大利拉斐尔时尚购物网
2019/03/12 全球购物
通信工程专业个人找工作求职信范文
2013/09/21 职场文书
农民工创业典型事迹
2014/01/25 职场文书
小学六年级学生评语
2014/04/22 职场文书
人力资源管理专业自荐书
2014/07/07 职场文书
2015年英语教研组工作总结
2015/05/23 职场文书
2015年仓库管理工作总结
2015/05/25 职场文书
二十年同学聚会致辞
2015/07/28 职场文书
怎样写好工作计划
2019/04/10 职场文书
涨工资申请书应该怎么写?
2019/07/08 职场文书
css3新特性的应用示例分析
2022/03/16 HTML / CSS