时间:2022-04-24 10:16:57 | 栏目:Python代码 | 点击:次
滑块拼图验证码的失败难度在于每次图片上缺口位置不一样,需识别图片上拼图的缺口位置,使用python的OpenCV库来识别到
pip 安装 opencv-python
pip installl opencv-python
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,提供了很多处理图片、视频的方法。
OpenCV库提供了一个方法(matchTemplate()):从一张较大的图片中搜索一张较小图片,计算出这张大图上各个区域和小图相似度。
调用这个方法后返回一个二维数组(numpy库中ndarray对象),从中就能拿到最佳匹配区域的坐标。
这种使用场景就是滑块验证码上背景图片是大图,滑块是小图。
准备2张图片
场景示例
先抠出2张图片,分别为background.png 和 target.png
计算缺口位置
import cv2 # 作者-上海悠悠 QQ交流群:717225969 # blog地址 https://www.cnblogs.com/yoyoketang/ def show(name): '''展示圈出来的位置''' cv2.imshow('Show', name) cv2.waitKey(0) cv2.destroyAllWindows() def _tran_canny(image): """消除噪声""" image = cv2.GaussianBlur(image, (3, 3), 0) return cv2.Canny(image, 50, 150) def detect_displacement(img_slider_path, image_background_path): """detect displacement""" # # 参数0是灰度模式 image = cv2.imread(img_slider_path, 0) template = cv2.imread(image_background_path, 0) # 寻找最佳匹配 res = cv2.matchTemplate(_tran_canny(image), _tran_canny(template), cv2.TM_CCOEFF_NORMED) # 最小值,最大值,并得到最小值, 最大值的索引 min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) top_left = max_loc[0] # 横坐标 # 展示圈出来的区域 x, y = max_loc # 获取x,y位置坐标 w, h = image.shape[::-1] # 宽高 cv2.rectangle(template, (x, y), (x + w, y + h), (7, 249, 151), 2) show(template) return top_left if __name__ == '__main__': top_left = detect_displacement("target.png", "background.png") print(top_left)
运行效果看到黑色圈出来的地方就说明找到了缺口位置
调试完成后去掉 show 的这部分代码
# 展示圈出来的区域 # x, y = max_loc # 获取x,y位置坐标 # w, h = image.shape[::-1] # 宽高 # cv2.rectangle(template, (x, y), (x + w, y + h), (7, 249, 151), 2) # show(template)
缺口的位置只需得到横坐标,距离左侧的位置top_left为184
参考博客:
https://zhuanlan.zhihu.com/p/65309386
https://blog.csdn.net/weixin_42081389/article/details/87935735
https://blog.csdn.net/qq_30815237/article/details/86812716
ps:python opencv破解滑动验证码之获取缺口位置的示例代码
破解滑块验证码的思路主要有2种:
#coding=utf-8 import cv2 import numpy as np from PIL import Image def get_element_slide_distance(): otemp = 'captcha2.png' oblk = 'captcha1.png' target = cv2.imread(otemp, 0) # 读取进行色度图片,转换为numpy中的数组类型数据 template = cv2.imread(oblk, 0) width, height = target.shape[::-1] # 获取缺口图数组的形状 -->缺口图的宽和高 temp = 'temp.jpg' # 将处理之后的图片另存 targ = 'targ.jpg' cv2.imwrite(temp, template) cv2.imwrite(targ, target) target = cv2.imread(targ) # 读取另存的滑块图 target = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY) # 进行色彩转换 # 去除白色部分 获取滑块正常大小 target = target[target.any(1)] target = abs(255 - target) # 获取色差的绝对值 cv2.imwrite(targ, target) # 保存图片 target = cv2.imread(targ) # 读取滑块 template = cv2.imread(temp) # 读取背景图 result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED) # 比较两张图的重叠区域 top, left = np.unravel_index(result.argmax(), result.shape) # 获取图片的缺口位置 #缺口位置 print((left, top, left + width, top + height)) # 背景图中的图片缺口坐标位置 #调用PIL Image 做测试 image = Image.open("captcha1.png") rectangle = (left + 3, top + 3, left + width - 3, top + height - 3) #去掉白色块的影响(上面去掉白色部分的功能并没有真的起作用) #切割 imagecrop = image.crop(rectangle) #保存切割的缺口 imagecrop.save("new_image.jpg") return left+3 distance = get_element_slide_distance() # 滑动距离误差校正,滑动距离*图片在网页上显示的缩放比-滑块相对的初始位置 distance = distance*(280/680) - 22
拖动轨迹
def generate_tracks1(XCoordinates): element = browser.find_element_by_xpath("//div[@class='secsdk-captcha-drag-icon sc-jKJlTe fsBatO']") ActionChains(browser).click_and_hold(on_element = element).perform() # # ActionChains(browser).move_by_offset(xoffset=0, yoffset=y - 445).perform() # # time.sleep(0.15) # print("第二步,拖动元素") distance = XCoordinates - 60 # 初速度 v = 0 # 单位时间为0.2s来统计轨迹,轨迹即0.2内的位移,越低看起来越丝滑!! t = 0.08 # 位移/轨迹列表,列表内的一个元素代表0.2s的位移 tracks = [] # 当前的位移 current = 0 # 到达mid值开始减速 mid = distance * 5 / 8 distance += 10 # 先滑过一点,最后再反着滑动回来 # a = random.randint(1,3) while current < distance: if current < mid: # 加速度越小,单位时间的位移越小,模拟的轨迹就越多越详细 a = random.randint(100, 200) # 加速运动 else: a = -random.randint(2, 10) # 减速运动 # 初速度 v0 = v # 0.2秒时间内的位移 s = v0 * t + 0.5 * a * (t ** 2) # 当前的位置 current += s # 添加到轨迹列表 tracks.append(round(s)) # 速度已经达到v,该速度作为下次的初速度 v = v0 + a * t if current > distance: break # 反着滑动到大概准确位置 # for i in range(4): # tracks.append(-random.randint(1, 3)) # for i in range(4): # tracks.append(-random.randint(1,3)) random.shuffle(tracks) count = 0 for item in tracks: print(item) count += item ActionChains(browser).move_by_offset(xoffset = item, yoffset = random.randint(-2, 2)).perform() # ActionChains(browser).move_to_element_with_offset(to_element=element, xoffset=XCoordinates-18,yoffset=y - 445).perform() # time.sleep(2) # # 释放鼠标 print(count) ActionChains(browser).release(on_element = element).perform()