本文将展示如何使用Dart语言实现极验滑动验证码的自动识别。从模拟点击到识别滑动缺口、计算位移并模拟拖动滑块。如果认证失败,则重复调用直到成功。
识别思路
模拟点击切换为滑动验证,并显示验证界面。
识别滑动缺口的位置,计算位移。
模拟拖动滑块。
若认证失败,重复调用。
详细过程及代码
初始化
首先,初始化Selenium WebDriver对象并配置参数。极验验证码测试页面的网址如下:更多内容联系1436423940
dart
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:image/image.dart' as img;
import 'package:webdriver/io.dart';
const String url = 'https://www.geetest.com/type/';
class CrackGeetest {
WebDriver driver;
CrackGeetest(this.driver);
Future<void> open() async {
await driver.get(url);
}
Future<void> close() async {
await driver.quit();
}
}
Future<void> main() async {
WebDriver driver = await createDriver(
uri: Uri.parse('http://localhost:4444/wd/hub'),
desired: {'browserName': 'chrome'},
);
CrackGeetest crackGeetest = CrackGeetest(driver);
await crackGeetest.open();
await crackGeetest.crack();
await crackGeetest.close();
}
extension on CrackGeetest {
Future<void> crack() async {
try {
await changeToSlide();
await getGeetestButton();
await waitPic();
var slider = await getSlider();
var image1 = await getGeetestImage('captcha1.png');
await deleteStyle();
var image2 = await getGeetestImage('captcha2.png');
var gap = getGap(image1, image2);
print('缺口位置: $gap');
gap -= 6;
var track = getTrack(gap);
await moveToGap(slider, track);
var success = await waitUntil(
By.className('geetest_success_radar_tip_content'), '验证成功');
if (success) {
print('验证成功');
} else {
print('Failed-Retry');
await crack();
}
} catch (e) {
print('Failed-Retry: $e');
await crack();
}
}
Future<void> changeToSlide() async {
var huadong = await driver.findElement(
const By.cssSelector('.products-content ul > li:nth-child(2)'));
await huadong.click();
}
Future<void> getGeetestButton() async {
var button = await driver.findElement(const By.cssSelector('.geetest_radar_tip'));
await button.click();
}
Future<void> waitPic() async {
await driver.findElement(const By.cssSelector('.geetest_popup_wrap'));
}
Future<WebElement> getSlider() async {
return await driver.findElement(const By.className('geetest_slider_button'));
}
Future<Uint8List> getGeetestImage(String name) async {
var screenshot = await driver.captureScreenshotAsList();
var file = File(name);
await file.writeAsBytes(screenshot);
return Uint8List.fromList(screenshot);
}
Future<void> deleteStyle() async {
await driver.execute('document.querySelectorAll("canvas")[2].style=""', []);
}
int getGap(Uint8List img1Bytes, Uint8List img2Bytes) {
var img1 = img.decodeImage(img1Bytes);
var img2 = img.decodeImage(img2Bytes);
int left = 60;
for (var i = left; i < img1!.width; i++) {
for (var j = 0; j < img1.height; j++) {
if (!isPixelEqual(img1.getPixel(i, j), img2!.getPixel(i, j))) {
return i;
}
}
}
return left;
}
bool isPixelEqual(int pixel1, int pixel2) {
var threshold = 60;
var r1 = img.getRed(pixel1);
var g1 = img.getGreen(pixel1);
var b1 = img.getBlue(pixel1);
var r2 = img.getRed(pixel2);
var g2 = img.getGreen(pixel2);
var b2 = img.getBlue(pixel2);
return (r1 - r2).abs() < threshold &&
(g1 - g2).abs() < threshold &&
(b1 - b2).abs() < threshold;
}
List<int> getTrack(int distance) {
var track = <int>[];
var current = 0;
var mid = (distance * 3 / 5).round();
var t = 0.2;
var v = 0.0;
distance += 14;
while (current < distance) {
var a = current < mid ? 2.0 : -1.5;
var v0 = v;
v = v0 + a * t;
var move = (v0 * t + 0.5 * a * t * t).round();
current += move;
track.add(move);
}
return track;
}
Future<void> moveToGap(WebElement slider, List<int> track) async {
await slider.clickAndHold();
for (var x in track) {
await driver.mouseMoveTo(slider, xOffset: x, yOffset: 0);
await Future.delayed(Duration(milliseconds: 50));
}
await slider.release();
}
Future<bool> waitUntil(By by, String text) async {
try {
var element = await driver.findElement(by);
var elementText = await element.text;
return elementText.contains(text);
} catch (_) {
return false;
}
}
}