戳这里→康康你手机号在过多少网站注册过!!!
友情推荐:新一代安全短信
* 验证码地址:https://007.qq.com/online.html
* 使用OpenCv模板匹配
* 成功率90%左右
* Java + Selenium + OpenCV
最近不少爬虫界面的朋友发现,原来可以识别腾讯防水墙的代码报错了, 怎么回事 ?
原来是腾讯防水墙做了升级
产品样例
背景图
和工具体混在一起的滑动图
截取图:
改进主要特点:
1 将滑块图片混合在工具条中,透明度不同,外边加了边框
2 iframe , 名字有原来的 tcaptcha_iframe ,变为 tcaptcha_iframe_dy
分析:
关键点在于滑块的变化,由于滑块混合,第一步肯定要做切割,
切割完后如果简单做二值化, 就会形成外框 ,这样下一步的就无法做模板匹配
掌握了特点, 就有了解决的思路,办法总比困难多
最后完美解决,识别率也不太高, 在 99% 左右吧
来吧!展示!
结果图1 : 五边形
结果图2 : 四边形
结果图3 :
注意!!!
· 在模拟滑动时不能按照相同速度或者过快的速度滑动,需要向人滑动时一样先快后慢,这样才不容易被识别。
模拟滑动代码↓↓↓
/**
* 模拟人工移动
* @param driver
* @param element页面滑块
* @param distance需要移动距离
*/
public static void move(WebDriver driver, WebElement element, int distance) throws InterruptedException {
int randomTime = 0;
if (distance > 90) {
randomTime = 250;
} else if (distance > 80 && distance <= 90) {
randomTime = 150;
}
List<Integer> track = getMoveTrack(distance - 2);
int moveY = 1;
try {
Actions actions = new Actions(driver);
actions.clickAndHold(element).perform();
Thread.sleep(200);
for (int i = 0; i < track.size(); i++) {
actions.moveByOffset(track.get(i), moveY).perform();
Thread.sleep(new Random().nextInt(300) + randomTime);
}
Thread.sleep(200);
actions.release(element).perform();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 根据距离获取滑动轨迹
* @param distance需要移动的距离
* @return
*/
public static List<Integer> getMoveTrack(int distance) {
List<Integer> track = new ArrayList<>();// 移动轨迹
Random random = new Random();
int current = 0;// 已经移动的距离
int mid = (int) distance * 4 / 5;// 减速阈值
int a = 0;
int move = 0;// 每次循环移动的距离
while (true) {
a = random.nextInt(10);
if (current <= mid) {
move += a;// 不断加速
} else {
move -= a;
}
if ((current + move) < distance) {
track.add(move);
} else {
track.add(distance - current);
break;
}
current += move;
}
return track;
}
看操作,no bb,直接上代码
/**
* v2 版本
*
* @param driver
* @return
*/
public RetEntity moveExec(WebDriver driver, boolean isLocal) {
File bFile = null;
File sFile = null;
RetEntity retEntity = new RetEntity();
retEntity.setRet(-1);
try {
// 获取到验证区域
WebElement iframe = ChromeDriverManager.waitElement(driver, By.id("tcaptcha_iframe_dy"), 100);
if (iframe == null) {
System.out.println("moveExec() tcaptcha_iframe|timeout!!!");
retEntity.setMsg("tcaptcha_iframe|timeout!!");
return retEntity;
}
driver.switchTo().frame(iframe);
sleep(500);
// 获取带阴影的背景图
WebElement wegSlideBg = driver.findElement(By.id("slideBg"));
String cssValue = wegSlideBg != null ? wegSlideBg.getCssValue("background-image") : null;
String bgUrl = (cssValue != null && cssValue.contains("\"")) ? cssValue.split("\"")[1] : null;
if (bgUrl == null) {
retEntity.setMsg("bgUrl=" + bgUrl);
return retEntity;
}
Long time = System.currentTimeMillis();
// 获取小图 URL (替换img_index=1为 img_index=0)
String slUrl = bgUrl.replaceAll("img_index=1", "img_index=0");
System.out.println("bgUrl=" + bgUrl);
System.out.println("slUrl=" + slUrl);
bFile = new File(dataPath + time + "-b.png");
sFile = new File(dataPath + time + "-s.png");
int getMode = 0;
Map<String, byte[]> retMap = (getMode == 0) ? getTwoImg(driver, bgUrl, slUrl, bFile, sFile) : getTwoImgOpen(driver, bgUrl, slUrl, bFile, sFile);
if (retMap != null) {
byte[] bigBytes = retMap.get("big");
byte[] smallBytes = retMap.get("small");
String distanceStr = null, width = null;
String ckSum = GenChecksumUtil.genChecksum(bigBytes);
String[] outArray = openCv2.getOpenCvDistance(ckSum, bigBytes, smallBytes, "tencent_v2", 3);
distanceStr = (outArray != null && outArray.length >= 2) ? outArray[1] : null;
width = (outArray != null && outArray.length >= 2) ? outArray[0] : null;
Double left = 27.0 * 672 / 340;// 起点距左边距离
Double act = (Double.parseDouble(distanceStr) - left - Double.parseDouble(width)) * 340.0 / 672.0;
Integer distance = act.intValue();
System.out.println("moveExec() distance(" + distanceStr + ")=" + distance);
if (distance == null || distance <= 0) {
return retEntity;
}
if (getMode != 0)
driver.switchTo().frame(iframe);
WebElement moveElemet = ChromeDriverManager.waitElement(driver, By.className("tc-slider-normal"), 500);
sleep(500);
// 滑动
GeetCanvasApi.move(driver, moveElemet, distance);
sleep(400);
// 滑动结果
String gtInfo = ChromeDriverManager.waitElement(driver, By.id("statusSuccess"), 100).getText();
if (gtInfo == null || "".equals(gtInfo)) {
sleep(200);
gtInfo = ChromeDriverManager.waitElement(driver, By.id("statusError"), 100).getText();
}
System.out.println("moveExec() gtInfo=" + gtInfo);
if (gtInfo.contains("验证成功")) {
retEntity.setRet(0);
retEntity.setMsg(gtInfo);
logger.info(retEntity.toString());
} else if (gtInfo.contains("再试一次") || gtInfo.contains("恍惚了") || gtInfo.contains("半路丢了")) {
retEntity.setRet(-1);
retEntity.setMsg("失败");
}
} else {
logger.error("retMap=" + retMap);
retEntity.setMsg("retMap=" + retMap);
return retEntity;
}
return retEntity;
} catch (Exception e) {
StringBuffer er = new StringBuffer("moveExec() " + e.toString() + "\n");
for (StackTraceElement elment : e.getStackTrace())
er.append(elment.toString() + "\n");
logger.error(er.toString());
System.out.println(er.toString());
retEntity.setMsg(er.toString());
return retEntity;
} finally {
if (retEntity.getRet() == 0) {
System.out.println("moveExec() del file...");
if (bFile != null)
bFile.delete();
if (sFile != null)
sFile.delete();
}
}
}
private Map<String, byte[]> getTwoImg(WebDriver driver, String bgUrl, String slUrl, File bFile, File sFile) {
try {
FileUtils.copyURLToFile(new URL(bgUrl), bFile);
FileUtils.copyURLToFile(new URL(slUrl), sFile);
BufferedImage sBI = ImageIO.read(sFile);
sBI = sBI.getSubimage(135, 478, 129, sBI.getHeight() - 478);
ImageIO.write(sBI, "png", sFile);
byte[] bigBytes = FileUtils.readFileToByteArray(bFile);
byte[] smallBytes = FileUtils.readFileToByteArray(sFile);
Map<String, byte[]> retMap = new HashMap<String, byte[]>();
retMap.put("big", bigBytes);
retMap.put("small", smallBytes);
return retMap;
} catch (Exception e) {
StringBuffer er = new StringBuffer("getTwoImgOpen() " + e.toString() + "\n");
for (StackTraceElement elment : e.getStackTrace())
er.append(elment.toString() + "\n");
logger.error(er.toString());
System.out.println(er.toString());
return null;
}
}
/**
*
* @param mat
* 二值化图像
*/
public static void binaryzation(Mat mat) {
int BLACK = 0;
int WHITE = 255;
int ucThre = 0, ucThre_new = 127;
int nBack_count, nData_count;
int nBack_sum, nData_sum;
int nValue;
int i, j;
int width = mat.width(), height = mat.height();
// 寻找最佳的阙值
while (ucThre != ucThre_new) {
nBack_sum = nData_sum = 0;
nBack_count = nData_count = 0;
for (j = 0; j < height; ++j) {
for (i = 0; i < width; i++) {
nValue = (int) mat.get(j, i)[0];
if (nValue > ucThre_new) {
nBack_sum += nValue;
nBack_count++;
} else {
nData_sum += nValue;
nData_count++;
}
}
}
nBack_sum = nBack_sum / nBack_count;
nData_sum = nData_sum / nData_count;
ucThre = ucThre_new;
ucThre_new = (nBack_sum + nData_sum) / 2;
}
// 二值化处理
int nBlack = 0;
int nWhite = 0;
for (j = 0; j < height; ++j) {
for (i = 0; i < width; ++i) {
nValue = (int) mat.get(j, i)[0];
if (nValue > ucThre_new) {
mat.put(j, i, WHITE);
nWhite++;
} else {
mat.put(j, i, BLACK);
nBlack++;
}
}
}
// 确保白底黑字
if (nBlack > nWhite) {
for (j = 0; j < height; ++j) {
for (i = 0; i < width; ++i) {
nValue = (int) (mat.get(j, i)[0]);
if (nValue == 0) {
mat.put(j, i, WHITE);
} else {
mat.put(j, i, BLACK);
}
}
}
}
}
// 延时加载
private static WebElement waitWebElement(WebDriver driver, By by, int count) throws Exception {
WebElement webElement = null;
boolean isWait = false;
for (int k = 0; k < count; k++) {
try {
webElement = driver.findElement(by);
if (isWait)
System.out.println(" ok!");
return webElement;
} catch (org.openqa.selenium.NoSuchElementException ex) {
isWait = true;
if (k == 0)
System.out.print("waitWebElement(" + by.toString() + ")");
else
System.out.print(".");
Thread.sleep(50);
}
}
if (isWait)
System.out.println(" outTime!");
return null;
}
戳这里→康康你手机号在过多少网站注册过!!!
友情推荐:新一代安全短信
相关阅读
谷歌图形验证码在AI 面前已经形同虚设,所以谷歌宣布退出验证码服务, 那么当所有的图形验证码都被破解时
《腾讯防水墙滑动拼图验证码》
《百度旋转图片验证码》
《网易易盾滑动拼图验证码》
《顶象区域面积点选验证码》
《顶象滑动拼图验证码》
《极验滑动拼图验证码》
《使用深度学习来破解 captcha 验证码》
《验证码终结者-基于CNN+BLSTM+CTC的训练部署套件》