使用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 相关文章推荐
使用jQuery.Validate进行客户端验证(初级篇) 不使用微软验证控件的理由
Jun 28 Javascript
jquery的ajax请求全面了解
Mar 20 Javascript
Function.prototype.bind用法示例
Sep 16 Javascript
JS 操作Array数组的方法及属性实例解析
Jan 08 Javascript
javascript图片预加载完整实例
Dec 10 Javascript
javascript中类的定义方式详解(四种方式)
Dec 22 Javascript
JavaScript实现下拉菜单的显示和隐藏
Jan 05 Javascript
Angular 页面跳转时传参问题
Aug 01 Javascript
Node.js实现文件上传的示例
Jun 28 Javascript
JS实现二维数组横纵列转置的方法
Apr 17 Javascript
小程序识别身份证,银行卡,营业执照,驾照的实现
Nov 05 Javascript
js 获取扫码枪输入数据的方法
Jun 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
关于BIG5-HKSCS的解决方法
2007/03/20 PHP
为IP查询添加GOOGLE地图功能的代码
2010/08/08 PHP
php数组函数序列之asort() - 对数组的元素值进行升序排序,保持索引关系
2011/11/02 PHP
php抽奖小程序的实现代码
2013/06/18 PHP
php实现的太平洋时间和北京时间互转的自定义函数分享
2014/08/19 PHP
php打包压缩文件之ZipArchive方法用法分析
2016/04/30 PHP
PHP5.5.15+Apache2.4.10+MySQL5.6.20配置方法分享
2016/05/06 PHP
php5对象复制、clone、浅复制与深复制实例详解
2019/08/14 PHP
PHP的Trait机制原理与用法分析
2019/10/18 PHP
jQuery Ajax 实例全解析
2011/04/20 Javascript
兼容主流浏览器的iframe自适应高度js脚本
2014/01/10 Javascript
js表格排序实例分析(支持int,float,date,string四种数据类型)
2015/05/06 Javascript
JS弹出对话框实现方法(三种方式)
2015/12/18 Javascript
JS定时器使用,定时定点,固定时刻,循环执行详解
2016/05/31 Javascript
利用Angularjs和bootstrap实现购物车功能
2016/08/31 Javascript
js实现目录链接,内容跟着目录滚动显示的简单实例
2016/10/15 Javascript
手机移动端实现 jquery和HTML5 Canvas的幸运大奖盘特效
2016/12/06 Javascript
简单实现jQuery上传图片显示预览功能
2020/06/29 jQuery
vue中轮训器的使用
2019/01/27 Javascript
js中对象与对象创建方法的各种方法
2019/02/27 Javascript
jsonp跨域获取百度联想词的方法分析
2019/05/13 Javascript
laravel-admin 与 vue 结合使用实例代码详解
2019/06/04 Javascript
Vue 用Vant实现时间选择器的示例代码
2019/10/25 Javascript
让IDE识别webpack的别名alias的实现方法
2020/05/06 Javascript
[51:05]DOTA2上海特级锦标赛主赛事日 - 5 败者组决赛Liquid VS EG第一局
2016/03/06 DOTA
python判断字符串是否包含子字符串的方法
2015/03/24 Python
Python使用PIL库实现验证码图片的方法
2016/03/11 Python
python队列通信:rabbitMQ的使用(实例讲解)
2017/12/22 Python
解决Django Static内容不能加载显示的问题
2019/07/28 Python
Python Pillow.Image 图像保存和参数选择方式
2020/01/09 Python
使用 css3 实现圆形进度条的示例
2017/07/05 HTML / CSS
编写一个 C 函数,该函数在一个字符串中找到可能的最长的子字符串,且该字符串是由同一字符组成的
2015/07/23 面试题
使用Vue.js和MJML创建响应式电子邮件
2021/03/23 Vue.js
国际会议邀请函范文
2014/01/16 职场文书
机械工程及自动化专业求职信
2014/09/03 职场文书
关于迟到的检讨书
2015/05/06 职场文书