首页 前端知识 使用TypeScript实现极验滑动验证码破解

使用TypeScript实现极验滑动验证码破解

2024-09-04 23:09:03 前端知识 前端哥 181 62 我要收藏


本文将介绍如何使用TypeScript和Selenium WebDriver来实现极验滑动验证码的自动识别与破解。我们将详细讲解每一步的实现,包括模拟点击、识别滑动缺口、计算位移以及模拟拖动滑块。

识别思路
模拟点击切换为滑动验证,并显示验证界面。
识别滑动缺口的位置,计算位移。
模拟拖动滑块。
若认证失败,重复调用。
实现步骤与代码
初始化
首先,初始化Selenium WebDriver对象并配置参数。极验验证码测试页面的网址如下:

typescript

import { Builder, By, until, WebDriver } from 'selenium-webdriver';
import { promises as fs } from 'fs';
import Jimp from 'jimp';

const BORDER = 6;
const URL = 'https://www.geetest.com/type/';

class CrackGeetest {
    private driver: WebDriver;

    constructor() {
        this.driver = new Builder().forBrowser('chrome').build();
    }

    async open() {
        await this.driver.get(URL);
    }

    async close() {
        await this.driver.quit();
    }

    async changeToSlide() {
        const slideOption = await this.driver.wait(until.elementLocated(By.css('.products-content ul > li:nth-child(2)')), 10000);
        await slideOption.click();
    }

    async getGeetestButton() {
        const button = await this.driver.wait(until.elementLocated(By.css('.geetest_radar_tip')), 10000);
        await button.click();
    }

    async waitPic() {
        await this.driver.wait(until.elementLocated(By.css('.geetest_popup_wrap')), 10000);
    }

    async getScreenshot(): Promise<Buffer> {
        const screenshot = await this.driver.takeScreenshot();
        return Buffer.from(screenshot, 'base64');
    }

    async getPosition() {
        const img = await this.driver.findElement(By.className('geetest_canvas_img'));
        const location = await img.getRect();
        return location;
    }

    async getSlider() {
        const slider = await this.driver.wait(until.elementLocated(By.className('geetest_slider_button')), 10000);
        return slider;
    }

    async getGeetestImage(filename: string) {
        const { x, y, width, height } = await this.getPosition();
        const screenshot = await this.getScreenshot();
        const image = await Jimp.read(screenshot);
        image.crop(x, y, width, height);
        await image.writeAsync(filename);
        return image;
    }

    async deleteStyle() {
        await this.driver.executeScript('document.querySelectorAll("canvas")[2].style=""');
    }

    isPixelEqual(img1: Jimp, img2: Jimp, x: number, y: number): boolean {
        const threshold = 60;
        const pixel1 = Jimp.intToRGBA(img1.getPixelColor(x, y));
        const pixel2 = Jimp.intToRGBA(img2.getPixelColor(x, y));
        return Math.abs(pixel1.r - pixel2.r) < threshold &&
               Math.abs(pixel1.g - pixel2.g) < threshold &&
               Math.abs(pixel1.b - pixel2.b) < threshold;
    }

    async getGap(img1: Jimp, img2: Jimp): Promise<number> {
        const left = 60;
        for (let i = left; i < img1.bitmap.width; i++) {
            for (let j = 0; j < img1.bitmap.height; j++) {
                if (!this.isPixelEqual(img1, img2, i, j)) {
                    return i;
                }
            }
        }
        return left;
    }

    getTrack(distance: number): number[] {
        const track = [];
        let current = 0;
        const mid = distance * 3 / 5;
        const t = 0.2;
        let v = 0;
        distance += 14;

        while (current < distance) {
            let a;
            if (current < mid) {
                a = 2;
            } else {
                a = -1.5;
            }
            const v0 = v;
            v = v0 + a * t;
            const move = v0 * t + 0.5 * a * t * t;
            current += move;
            track.push(Math.round(move));
        }
        return track;
    }

    async moveToGap(slider: WebDriver, tracks: number[]) {
        await this.driver.actions().clickAndHold(slider).perform();
        for (const move of tracks) {
            await this.driver.actions().move({ x: move, y: 0 }).perform();
        }
        const backTracks = [-1, -1, -2, -2, -3, -2, -2, -1, -1];
        for (const move of backTracks) {
            await this.driver.actions().move({ x: move, y: 0 }).perform();
        }
        await this.shakeMouse();
        await this.driver.actions().release().perform();更多内容联系1436423940
    }

    async shakeMouse() {
        await this.driver.actions().move({ x: -3, y: 0 }).perform();
        await this.driver.actions().move({ x: 2, y: 0 }).perform();
    }

    async crack() {
        try {
            await this.open();
            await this.changeToSlide();
            await this.getGeetestButton();
            await this.waitPic();
            const slider = await this.getSlider();
            const image1 = await this.getGeetestImage('captcha1.png');
            await this.deleteStyle();
            const image2 = await this.getGeetestImage('captcha2.png');
            const gap = (await this.getGap(image1, image2)) - BORDER;
            const track = this.getTrack(gap);
            await this.moveToGap(slider, track);
            const success = await this.driver.wait(until.elementTextContains(await this.driver.findElement(By.className('geetest_success_radar_tip_content')), '验证成功'), 10000);
            console.log(success);
        } catch (error) {
            console.error('Failed-Retry', error);
            await this.crack();
        } finally {
            await this.close();
        }
    }
}

(async () => {
    const crack = new CrackGeetest();
    await crack.crack();
})();

转载请注明出处或者链接地址:https://www.qianduange.cn//article/17673.html
标签
评论
发布的文章

javascript jQuery

2024-09-21 22:09:33

【若依】表格固定列宽

2024-09-21 22:09:30

Knockout-jQueryUI 使用指南

2024-09-21 22:09:29

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!