この記事では主に、Puppeteer を使用して Jiexi をクラックするためのスライディング検証機能を紹介します。基本的なプロセス コードの実装が詳しく紹介されています。必要な方は参考にしてください。
1.フロントエンド Web サイトを開き、クリックしてログインします。 2. アカウント番号とパスワードを入力します。
3. 認証ボタンをクリックし、スライドして認証し、最後にログインに成功します。
コードの実装:
githubでチェックアウトできます。 具体的なコードは次のとおりです:
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" } }
これら2つのファイルをフォルダーに保存し、ターミナルを現在のパスに切り替えます
2。 npm i3. フロントエンドネットワークのアカウントとパスワードを入力します4. ノードの実行
次のデモは 4 つのステップに分かれています:
1. ログインを開きます。のページにアクセスし、事前に記入したアカウントパスワードを入力します。
2. 初めてスライダーをドラッグすると、「モンスターに食べられました」というメッセージが表示されるので、新しい画像のギャップ距離が再計算されます。
3. 次に、3回目のドラッグ後に「正しく結合されていません」というメッセージが表示されるので、もう一度ドラッグします。 4. 認証に成功し、ログインします。 (GIF 上にマウスを置いてデモンストレーション効果を確認するか、新しいウィンドウにドラッグして GIF を開きます)
手順 1 スライド検証には 3 つのキャンバスがあります。 、そのうちクラス名のみが 'geetest_canvas_fullbg ' とピクセル差比較用の 'geetest_canvas_bg' です。 ps: 前者は全体像、後者は切り欠きのある絵です。2. ノッチのあるすべての画像には誤解を招く影があるため、ピクセルの差を比較すると、計算された距離がそれぞれ誤解を招く影とノッチになります。したがって、スライド距離の値は、「{min:res[0]-7,max:res[res.length-1]-54}」とします。ノッチが誤解を招く影の左側にある場合、min (最小距離) の値はスライド距離になります。それ以外の場合、max (最大距離) からスライダーの幅を引いた値になります。
3. スライディングの結果は、検証成功、食べられた、失敗の 3 つの状況に分けられます。 「食べる」は画像を再リクエストするため、スライドする前に距離が再計算されます。「失敗」は 4 回実行しても失敗する場合、プロセス全体が再実行されます。
上記は私があなたのためにまとめたものです。
関連記事:
スワイパーでの動的読み込みデータのスライド失敗の問題を解決するにはどうすればよいですか?
ES6 のアロー関数に関するこれについて質問はありますか?
vueでecharts3.0adaptiveを使用する方法は何ですか?以上がpuppeteer を使用して JiExperience のスライディング検証コードをクラックする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。