欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-11-03 08:05:22
基本的流程: 1. 打开前端网,点击登录。 2. 填写账号,密码。 3. 点解验证按钮,通过滑动验证,最后成功登陆。 代码实现: github上可以checkou...

基本的流程:

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破解极验的滑动验证码,希望对大家有所帮助