使用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编程起步(第五课)
Jan 10 Javascript
JQuery动画animate的stop方法使用详解
May 09 Javascript
js设置控件的隐藏与显示的两种方法
Aug 21 Javascript
jQuery实现的多屏图像图层切换效果实例
May 07 Javascript
JavaScript实现DIV层拖动及动态增加新层的方法
May 12 Javascript
探析浏览器执行JavaScript脚本加载与代码执行顺序
Jan 12 Javascript
js判断鼠标位置是否在某个div中的方法
Feb 26 Javascript
JS 滚动事件window.onscroll与position:fixed写兼容IE6的回到顶部组件
Oct 10 Javascript
jQuery webuploader分片上传大文件
Nov 07 Javascript
echarts饼图扇区添加点击事件的实例
Oct 16 Javascript
Vue 实现把表单form数据 转化成json格式的数据
Oct 29 Javascript
js和jquery判断数据类型的4种方法总结
Aug 28 jQuery
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
php 随机数的产生、页面跳转、件读写、文件重命名、switch语句
2009/08/07 PHP
php调用MySQL存储过程的方法集合(推荐)
2013/07/03 PHP
怎样使用php与jquery设置和读取cookies
2013/08/08 PHP
二进制交叉权限微型php类分享
2014/02/07 PHP
jQuery UI 应用不同Theme的办法
2010/09/12 Javascript
基于jQuery架构javascript基础体系
2011/01/01 Javascript
js/jquery去掉空格,回车,换行示例代码
2013/11/05 Javascript
laytpl 精致巧妙的JavaScript模板引擎
2014/08/29 Javascript
实现前后端数据交互方法汇总
2015/04/07 Javascript
ionic js 模型 $ionicModal 可以遮住用户主界面的内容框
2016/06/06 Javascript
JavaScript学习笔记整理_简单实现枚举类型,扑克牌应用
2016/09/19 Javascript
vue-cli入门之项目结构分析
2017/04/20 Javascript
JS原生轮播图的简单实现(推荐)
2017/07/22 Javascript
微信小程序实现点击按钮修改文字大小功能【附demo源码下载】
2017/12/06 Javascript
Node.js net模块功能及事件监听用法分析
2019/01/05 Javascript
JavaScript多种滤镜算法实现代码实例
2019/12/10 Javascript
全面解析Python的While循环语句的使用方法
2015/10/13 Python
Pycharm技巧之代码跳转该如何回退
2017/07/16 Python
Python数据结构与算法之图的广度优先与深度优先搜索算法示例
2017/12/14 Python
python3 requests中使用ip代理池随机生成ip的实例
2018/05/07 Python
python顺序的读取文件夹下名称有序的文件方法
2018/07/11 Python
wxPython的安装与使用教程
2018/08/31 Python
使用tensorflow实现线性svm
2018/09/07 Python
Pandas中DataFrame的分组/分割/合并的实现
2019/07/16 Python
Python 装饰器原理、定义与用法详解
2019/12/07 Python
丝芙兰巴西官方商城:SEPHORA巴西
2016/10/31 全球购物
Rag & Bone官网:瑞格布恩高级成衣
2018/04/19 全球购物
struct与class的区别
2014/02/03 面试题
如何写一个Java类既可以用作applet也可以用作java应用
2016/01/18 面试题
运动会广播稿300字
2014/01/10 职场文书
亲戚结婚的请假条
2014/02/11 职场文书
幼儿园中班下学期评语
2014/04/18 职场文书
竞选班干部演讲稿
2014/04/24 职场文书
中华魂放飞梦想演讲稿
2014/08/26 职场文书
党员公开承诺书2015
2015/01/21 职场文书
2019最新企业员工考勤管理制度(通用版)!
2019/07/02 职场文书