使用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写的select支持上下键、首字母筛选以及回车取值的功能
Sep 09 Javascript
javascript实现des解密加密全过程
Apr 03 Javascript
$(document).ready(function() {})不执行初始化脚本
Jun 19 Javascript
一个简单的动态加载js和css的jquery代码
Sep 01 Javascript
原生JS:Date对象全面解析
Sep 06 Javascript
vue2实现可复用的轮播图carousel组件详解
Nov 27 Javascript
vue项目总结之文件夹结构配置详解
Dec 13 Javascript
vuex直接赋值的三种方法总结
Sep 16 Javascript
jQuery实现的中英文切换功能示例
Jan 11 jQuery
vue项目出现页面空白的解决方案
Oct 31 Javascript
解决vue.js中settimeout遇到的问题(时间参数短效果不稳定)
Jul 21 Javascript
OpenLayers实现图层切换控件
Sep 25 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
PHP最常用的2种设计模式工厂模式和单例模式介绍
2012/08/14 PHP
PHP实现PDO操作mysql存储过程示例
2019/02/13 PHP
jQuery选择头像并实时显示的代码
2010/06/27 Javascript
javascript中的注释使用与注意事项小结
2011/09/20 Javascript
js点击更换背景颜色或图片的实例代码
2013/06/25 Javascript
JQuery获取样式中的background-color颜色值的问题
2013/08/20 Javascript
javascript页面渲染速度测试脚本分享
2014/04/15 Javascript
js实现类似新浪微博首页内容渐显效果的方法
2015/04/10 Javascript
Javascript中的方法和匿名方法实例详解
2015/06/13 Javascript
使用AngularJS制作一个简单的RSS阅读器的教程
2015/06/18 Javascript
深入理解react-router@4.0 使用和源码解析
2017/05/23 Javascript
React-Router如何进行页面权限管理的方法
2017/12/06 Javascript
微信小程序支付功能 php后台对接完整代码分享
2018/06/12 Javascript
vue组件间通信六种方式(总结篇)
2019/05/15 Javascript
微信小程序如何调用新闻接口实现列表循环
2019/07/02 Javascript
vue.js 输入框输入值自动过滤特殊字符替换中问标点操作
2020/08/31 Javascript
[55:35]VGJ.S vs Mski Supermajor小组赛C组 BO3 第二场 6.3
2018/06/04 DOTA
python实现textrank关键词提取
2018/06/22 Python
python实现的读取网页并分词功能示例
2019/10/29 Python
PyQT5 emit 和 connect的用法详解
2019/12/13 Python
python 多进程队列数据处理详解
2019/12/23 Python
Pytorch模型转onnx模型实例
2020/01/15 Python
python代码实现TSNE降维数据可视化教程
2020/02/28 Python
如何更换python默认编辑器的背景色
2020/08/10 Python
python+excel接口自动化获取token并作为请求参数进行传参操作
2020/11/10 Python
50个强大璀璨的CSS3/JS技术运用实例
2010/02/27 HTML / CSS
html5 音乐播放器 audio 标签使用概述
2013/07/15 HTML / CSS
丝芙兰美国官网:SEPHORA美国
2016/08/03 全球购物
BCBG官网:BCBGMAXAZRIA
2017/12/29 全球购物
感恩老师的演讲稿
2014/05/06 职场文书
党员服务承诺书
2014/05/28 职场文书
交通运输局四风问题对照检查材料思想汇报
2014/10/09 职场文书
情侣之间的道歉短信
2015/05/12 职场文书
mysql如何配置白名单访问
2021/06/30 MySQL
使用Mysql计算地址的经纬度距离和实时位置信息
2022/04/29 MySQL
mysql 获取相邻数据项
2022/05/11 MySQL