目标
前两天发现个好玩的工具Selenium,可以模拟人进行游览器操作,赶紧趁热打铁玩个小demo,滑块验证现在使用普遍,就是为了验证是否是机器人,但是这个是可以破解的,且听我娓娓道来
思路
- 计算滑块距离
- 模拟人进行滑块拖动
解决
前提
Selenium 官网下载jar包,先搭建环境
第一个问题我在另一篇博客已经详细描述
现在是第二个问题如何拟人化的拖动滑块,滑的太快不行,太慢也不行,这里我提供别人用python的一种方案,可以用
public static void move(WebDriver driver, WebElement element, Integer[] track)
throws InterruptedException {
Actions actions = new Actions(driver);
// 按下滑块
new Actions(driver).clickAndHold(element).perform();
for (int i : track) {
actions.moveByOffset(i, 0).perform();
}
Thread.sleep(500);
//释放
actions.release(element).perform();
}
// 获取运动轨迹
public static Integer[] getTrack(int distance){
List<Integer> integers = new ArrayList<>();
// distance += 20;
int current = 0;
double mid = (distance * 3) / 4;
double t = 0.2;
double v = 0.0;
double v0 = 0;
double move = 0.0;
while (current < distance){
int a = 0;
if (current < mid){
a = 2;
}else {
a = -3;
}
v0 = v;
v = v0 + a * t;
move = v0 * t + (0.5) * a * t * t;
current += move;
integers.add((int) CommandUtil.round(move));
}
// integers.addAll(Stream.of(-3, -3, -2, -2, -2, -2, -2, -1, -3, -4).collect(Collectors.toList()));
return integers.toArray(new Integer[0]);
}
由于我们计算的距离不一定十分准确,我们可以重试
// 单个验证 重试次数
int retryCount = 0;
int i = 0;
WebElement tcaptchaButtonEle = null;
while (true){
// 3次 是滑块验证单个图验证次数最多出现3次,否则会换图的
if (retryCount % 3 == 0){
retryCount = 0;
// 滑块按钮元素
tcaptchaButtonEle = webDriver.findElementById("tcaptcha_drag_thumb");
System.out.println(tcaptchaButtonEle.getAttribute("class"));
// 滑块背景图
WebElement slideBgEle = webDriver.findElementById("slideBg");
String slideBgPicUrl = slideBgEle.getAttribute("src");
// 滑块元素
WebElement slideBlockEle = webDriver.findElementById("slideBlock");
String slideBlockPicUrl = slideBlockEle.getAttribute("src");
String style = slideBlockEle.getAttribute("style");
String[] split = style.split(";");
// html中滑块的宽度
double htmlBlockWidth = 0.0;
// html中滑块x坐标
double marginLeft = 0.0;
for (String s : split) {
if (s.contains("width")){
String px = s.replace("width: ", "").replace("px", "");
htmlBlockWidth = Double.parseDouble(px);
}else if (s.contains("left")){
String px = s.replace("left: ", "").replace("px", "");
marginLeft = Double.parseDouble(px);
}
}
System.out.println(htmlBlockWidth + "," + marginLeft);
try {
// 计算移动距离(基于上篇博客的代码)
i = SlideUtils.calculateOffset(slideBgPicUrl, slideBlockPicUrl, htmlBlockWidth, marginLeft);
// 误差
i -= 20;
} catch (Exception e) {
e.printStackTrace();
}
}else {
// 没有换图,那就不需要重新下载,直接修改距离
// 如果距离不对,减少挪动距离,这个参数视情况而定
i -= 15;
}
Thread.sleep(1000);
System.out.println("移动距离 ==> "+ i);
Integer[] track = getTrack(i);
System.out.println("移动轨迹 ==> " + JSON.toJSONString(track));
move(webDriver, tcaptchaButtonEle, track);
Thread.sleep(1000);
WebElement guideText = null;
try {
// 验证是否成功,因为滑块的图片基本会有这个字提示
// 拖动下方滑块完成拼图 去找这个字元素id
// 如果没有的话会报异常的,那就是通过了
guideText = webDriver.findElementById("guideText");
} catch (Exception e) {
System.out.println("验证通过");
break;
}
// Thread.sleep(3000);
System.out.println("验证失败等待进行下一次重试");
retryCount++;
}
// 回到父级的页面
webDriver.switchTo().parentFrame();
buttons = webDriver.findElementsByTagName("button");
for (WebElement button : buttons) {
String span = button.findElement(By.tagName("span")).getText();
// 点击登录
if (span.equals("登录")){
button.click();
Thread.sleep(2000);
break;
}
}
总结
好玩!!!