场景介绍:影刀内置了很多关于验证码的指令,足够应付众多场景的验证码校验,但是拼多多的双阴影滑块验证,由于只能捕获到一个大块元素,无法准确捕获到缺块、背景和拖拽滑块,并且背景的缺口会在用户鼠标点下拖拽滑块时随机偏移,此时显示的才是真实的缺口位置,所以目前的验证码指令就不适用了。(这里的验证码的在PC端打开手机版拼多多商城网页,弹出新网页的滑块验证,不是嵌入在某个网页内的。)

解决思路:先鼠标按下拖拽滑块,暴露出缺口的实际位置,通过元素截图分割把背景区域截取下来,用openCV模块进行缺口距离的识别,再用鼠标拖动对应距离即可。
获取拖拽滑块的坐标:
由于无法捕获到各个小元素,所以本文定位元素的思路是通过大块元素的总长度、总宽度以及元素在大块元素的相对位置去计算得出所需的元素坐标。例如拖拽滑块的位置可以通过指定从大块元素向右、向上偏移n个像素的距离,距离又可以通过大块元素的总长、宽度与滑块的相对位置系数相乘得到。横向距离:int((元素.right-元素.left)*0.1606805),纵向距离:int((元素.bottom-元素.top)*0.1985981),系数“0.1606805、0.1985981”为拖拽滑块位于大块元素的相对位置。


鼠标悬停到拖拽滑块后,再次获取相对于屏幕左上角的坐标,然后按下鼠标左键,使背景缺口变化,暴露出真实的缺口位置,并将大块元素截图下来,用于后面的裁剪和判断缺口距离。
大块元素截图如下:

用PIL模块将背景从这个截图中裁剪出来,得到:

代码:
# 裁剪背景图片
from PIL import Image
def cutbg(path): # 传入图片路径
img = Image.open(path)
lp = int(float(img.size[0]) * 0.0681818) # 左边距
rp = int(float(img.size[0]) * 0.9301346) # 右边距
top = int(float(img.size[1]) * 0.0581395) # 上边距
button = int(float(img.size[1]) * 0.6523255) # 下边距
box1 = (lp, top, rp, button)
image1 = img.crop(box1)
return image1 # 返回裁剪后的图片对象
把背景再次裁剪,得到左边的滑块部分和右边的缺口部分:

代码:
# 把背景图片分割成缺块部分和缺口部分(一分为二)
def cut_ab(img, save_path_a, save_path_b): # 传入背景图片对象以及裁剪后图片保存路径
img_a = img.copy()
lp = int(float(img.size[0]) * 0.03125) # 左边距
rp = int(float(img.size[0]) * 0.1953125) # 右边距
box1 = (lp, 0, rp, int(img.size[1]))
image_a = img_a.crop(box1)
image_a.save(save_path_a)
lp = int(float(img.size[0]) * 0.1953125) # 左边距
rp = int(img.size[0]) # 右边距
box1 = (lp, 0, rp, int(img.size[1]))
image_b = img.crop(box1)
image_b.save(save_path_b)
识别缺口距离:
代码:
# 识别图片返回缺口距离
import cv2
def get_x(path_a,path_b):
bg_img = cv2.imread(path_b) # 读取背景图片
tp_img = cv2.imread(path_a) # 读取滑块图片
bg_edge = cv2.Canny(bg_img, 100, 200) # 识别出图片的边缘
tp_edge = cv2.Canny(tp_img, 100, 200) # 识别出图片的边缘
bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB) # 将其图片格式转为RGB格式
tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB) # 将其图片格式转为RGB格式
res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED) # 缺口匹配
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # 寻找最优匹配
# 缺口的位置X轴坐标为max_loc[0]
# 左边滑块图片宽度为tp_img.shape[1]
# 两者相加,为缺口距离滑块的距离
x = max_loc[0] + int(tp_img.shape[1])
return x # 返回缺口距离
用main函数调用上面的函数:
import os
def main(path_img): # 传入截图的大块元素的图片路径
desk_path = os.path.join(os.path.expanduser('~'),"Desktop") # 这里调用了os模块获取桌面路径
path_a = desk_path + r"\yanzhengmaA.png"
path_b = desk_path + r"\yanzhengmaB.png"
img = cutbg(path_img)
cut_ab(img,path_a,path_b)
X = get_x(path_a,path_b)
到这里,最关键的缺口距离已经拿到了,后面只需要将该距离传给移动鼠标指令,移动到对应位置弹起鼠标左键,验证即可完成。

完成效果:
