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

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

识别思路
模拟点击切换为滑动验证,并显示验证界面。
识别滑动缺口的位置,计算位移。
模拟拖动滑块。更多内容访问ttocr.com或联系1436423940
若认证失败,重复调用。
实现步骤与代码
初始化
首先,初始化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();
})();

posted @   ttocr、com  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示