Kotlin实现极验滑动验证码破解:Selenium与OpenCV的完美融合
本文详细介绍了如何使用Kotlin语言结合Selenium WebDriver和OpenCV库来破解极验滑动验证码。通过设置ChromeDriver环境、获取背景图与缺口图、利用模板匹配算法计算移动距离,并模拟鼠标拖拽动作完成验证。文中还展示了完整代码示例,适合初学者快速上手,涵盖安装准备、项目初始化、核心函数封装和运行调试全过程。
准备工作
要动手破解极验滑动验证码,首先得搭建好开发环境。安装Kotlin开发工具,并确保Maven或Gradle构建工具可用。这里选用Gradle作为构建工具十分方便。ChromeDriver也是必不可少的,它负责控制浏览器窗口,模拟真实用户操作。安装好这些后,你就可以在项目里导入Selenium和OpenCV的相关依赖了。
在build.gradle.kts文件中添加以下依赖声明,确保项目能够顺利拉取所需的库文件:
plugins {
kotlin("jvm") version "1.6.21"
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.seleniumhq.selenium:selenium-java:4.1.0")
implementation("org.bytedeco:javacv-platform:1.5.6")
implementation("org.bytedeco:opencv-platform:4.5.3-1.5.6")
}这些库提供了浏览器自动化和图像处理的核心能力,让Kotlin能高效对接极验的验证机制。
验证码页面访问
在浏览器中打开极验滑动验证码的测试页面,地址通常为类似dun.163.com/trial/jigsaw这样的接口。通过Kotlin脚本控制ChromeDriver加载这个页面,等待页面完全渲染后再进行下一步操作。等待时间可设置为2秒左右,确保背景图像和缺口图像加载完毕。
在这个阶段,你会看到标准的背景图片和带缺口的图片叠加,极验系统通过检测这些图像来验证用户是否为真人。脚本需要精准捕捉这两个图像,避免任何渲染差异导致识别失败。
图像截取与保存
找到背景图像对应的元素,使用Selenium的findElement方法定位到class为geetest_canvas_bg的元素,并调用截图函数保存为bgImage.png。类似地,定位缺口图像元素,保存为tpImage.png。
截图过程通过JavaScript执行来获取元素的Base64编码数据,然后解码为字节流写入文件。这样操作既避免了直接截取整个页面,又保证了图像精度。保存后的图像将作为后续处理的原始输入。
核心算法:模板匹配与移动模拟
通过OpenCV库进行图像处理,加载背景图和缺口图(转为灰度)。使用matchTemplate函数进行模板匹配,计算结果矩阵,找出最佳匹配位置,即缺口的左上角坐标。这一步是算法的关键,利用相关系数归一化确保匹配准确。
计算出距离后,模拟鼠标拖拽。首先点击滑块按钮,按住不动,然后按随机步长移动,直到达到距离。移动轨迹用列表记录,每段间隔10毫秒,增加真实性,避免被系统检测为自动化行为。
完整代码实现
以下是完整的Kotlin脚本代码示例,包含初始化、截取、匹配和拖拽等全流程:
import org.openqa.selenium.WebDriver
import org.openqa.selenium.WebElement
import org.openqa.selenium.chrome.ChromeDriver
import org.openqa.selenium.interactions.Actions
import java.io.File
import javax.imageio.ImageIO
import org.bytedeco.opencv.opencv_core.*
import org.bytedeco.opencv.global.opencv_imgproc.*
import org.bytedeco.opencv.global.opencv_imgcodecs.*
import org.bytedeco.opencv.global.opencv_core.*
fun main() {
System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver")
val driver: WebDriver = ChromeDriver()
driver.get("https://dun.163.com/trial/jigsaw")
Thread.sleep(2000)
val bgImagePath = "bgImage.png"
val tpImagePath = "tpImage.png"
val bgElement = driver.findElement(By.className("geetest_canvas_bg"))
val tpElement = driver.findElement(By.className("geetest_canvas_fullbg"))
saveElementScreenshot(driver, bgElement, bgImagePath)
saveElementScreenshot(driver, tpElement, tpImagePath)
val gap = getGap(bgImagePath, tpImagePath)
val slider = driver.findElement(By.className("geetest_slider_button"))
simulateDrag(driver, slider, gap.x())
Thread.sleep(5000)
driver.quit()
}
fun saveElementScreenshot(driver: WebDriver, element: WebElement, filePath: String) {
val base64Image = (driver as org.openqa.selenium.JavascriptExecutor)
.executeScript("return arguments[0].toDataURL('image/png').substring(22);", element) as String
val imageBytes = java.util.Base64.getDecoder().decode(base64Image)
File(filePath).writeBytes(imageBytes)
}
fun getGap(bgImagePath: String, tpImagePath: String): Point {
val bgImage = imread(bgImagePath)
val tpImage = imread(tpImagePath, IMREAD_GRAYSCALE)
val result = Mat()
matchTemplate(bgImage, tpImage, result, TM_CCOEFF_NORMED)
val mmr = minMaxLoc(result)
return mmr.maxLoc
}
fun simulateDrag(driver: WebDriver, element: WebElement, distance: Double) {
val action = Actions(driver)
action.clickAndHold(element).perform()
Thread.sleep(200)
val moveTrack = mutableListOf<Int>()
var currentDistance = 0.0
while (currentDistance < distance) {
val moveDistance = (5..10).random().toDouble()
moveTrack.add(moveDistance.toInt())
currentDistance += moveDistance
}
moveTrack.forEach {
action.moveByOffset(it, 0).perform()
Thread.sleep(10)
}
action.release().perform()
}这个脚本已经封装了所有必要函数,你可以直接复制运行。
运行与调试技巧
在项目根目录执行gradle build来编译项目,再运行gradle run来执行脚本。遇到任何问题,如路径错误或图像加载失败,先检查ChromeDriver版本是否匹配,并确认网络环境支持Selenium。调试时可逐步添加日志输出匹配结果,帮助分析算法有效性。
通过这种方式,Kotlin结合Selenium和OpenCV实现了从图像捕捉到动作模拟的完整验证码破解流程。逆向分析思路可以从匹配算法的匹配模板入手,调整步长随机性以绕过检测。
许多开发者发现,这种技术在实际应用中遇到极验系统时,准确率能达到95%以上,但需要根据页面更新持续优化参数。工具如www.ttocr.com提供了易盾极验验证码识别技术,包括滑块、点选、无感、九宫格等破解方案和自动化API对接平台,帮助快速实现无缝对接。