问题来源
拼图验证码属于比较常见的一种验证码了,大部分情况下使用官方的验证码拼图/或者验证码免费版都能处理掉。
小白遇到的这个属于较为特殊的一种。页面上是canvas标签而非常见的div标签,如图所示
这一类验证码最大的问题在于元素不好捕获,canvas是一个矩形区域的画布,可以用 JavaScript 在上面绘画。
缺口图片和背景图片直接捕获的话,都是这个画布的区域(比如小白展示的这个网站),此前社区也有个类似的问题,小白测试了下的速度不是特别快。
目前也测试过了现有的几个指令,效果不是很好就是了,就打算自己折腾下
突破点
因为验证码肯定是有图片来源的,小白测试下来发现,点击登陆/刷新验证码的时候都有发送网络交互,交互的结果就是下载这两张图片。
那么剩下的就是很简单了,获取这网络交互的结果,将监听到的数据转化为图片,在做缺口识别。
图片转化部分
监听到的数据是这样的字典信息,可以通过字典的type的值判断是否为图片(image类型)
图片的转化
输入监听的数据的body信息,设置保存路径,可以将图片保存到指定位置
def new_img(img_data,save_path):
# 去掉数据头部的描述信息
image_data = img_data.replace('image/png;base64,', '')
# 解码base64数据
decoded_data = base64.b64decode(image_data)
# 将数据保存成图片文件
with open(save_path, 'wb') as file:
file.write(decoded_data)
下载图片了之后,剩下的做法就比较多了,归根结底就是计算缺口的位置信息(从图片的左侧到做缺口的位置,也就是横坐标)
注意!这边小白默认是没有计算缩放比例的,有的时候canvas标签的大小和图片的大小对不上的话,需要使用指令获取图片大小,然后和canvas画布的大小计算缩放比,最后得出的横坐标再乘以这个缩放比
指令:
处理图片获取坐标的话,目前是几个方法,小白也都介绍下吧
1.使用OpenCV库
介绍及案例可以参考社区小伙伴的帖子:
https://www.yingdao.com/community/detaildiscuss?id=6f5ac7d1-6d58-41cf-82c1-2054464bb3c4
注意点:
如果使用这个指令或者OpenCV库处理图片的时,提示类似这样乱码的情况或者提示,就需要检查截图或者本机的文件路径了。
OpenCV库暂不支持直接读取含有中文字符的路径的图片。
关于这个问题,小白也尝试过将文件路径重新编码,然后去读取。最后发现还是没办法正常执行。
后面发现严格来讲,imread并不是不支持中文字符路径,而是不支持Non-ascii文件路径。
那么方向就比较清楚了,先用其他支持中文字符路径的扩展库读取图片数据,再用OpenCV库从内存读取图片信息。(此处以numpy为例子)
numpy、OpenCV读取中文字符路径图片参考:
import io
import numpy as np
import cv2
# 读取图片路径
image_path = "假设这边是中文字符路径图片"
# 使用BytesIO对象读取图片
with open(image_path, "rb") as f:
img_bytes = f.read()
# 将字节数据转换为NumPy数组
img_array = np.frombuffer(img_bytes, np.uint8)
# 将NumPy数组转换为OpenCV图像
img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
完整的计算缺口过程
import cv2
import numpy as np
img_file_bg=r'C:\Users\未白\Desktop\test11.png'
img_file_tp=r'C:\Users\未白\Desktop\test22.png'
# np.frombuffer()函数可以接受二进制字节数据,但也可以接受其他类型的数据,例如图片路径。
bg_img=cv2.imdecode(np.fromfile(img_file_bg,dtype=np.uint8),-1)
tp_img=cv2.imdecode(np.fromfile(img_file_tp,dtype=np.uint8),-1)
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)
tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)
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]
print("缺口的横坐标:", X)
2.使用ddddocr扩展库
真不愧是带带弟弟,连小白也能轻松使用这个库。(主要还是免费,而且经小白实际测试下来,准确度还是不错的)具体使用方式可以参考这个链接:https://www.qinglite.cn/doc/8820647771fe47749
这边只介绍验证码识别的这部分
import ddddocr
img_file_bg=r'C:\Users\未白\Desktop\test11.png'
img_file_tp=r'C:\Users\未白\Desktop\test22.png'
det = ddddocr.DdddOcr(det=False, ocr=False)
#读取背景图和缺口图
with open(img_file_tp, 'rb') as f:
target_bytes = f.read()
with open(img_file_bg, 'rb') as f:
background_bytes = f.read()
res = det.slide_match(target_bytes, background_bytes, simple_target=True)
print(res)
3.使用影刀自带的验证码处理指令
如果真的觉得麻烦,不想去写的话,也可以用影刀自带的验证码处理指令,也支持本地验证码识别。
比如这个验证码识别指令,也能获取到缺口的横坐标信息。
得到横坐标信息之后就好办了,一般情况,如果图片没有做缩放,直接拿着这个缺口的横坐标信息,去拖动滑块就行了。小白目前实测下来,准确度还是比较高的,基本上一两次就过了。
效果如下:
作者:未白 来源:影刀社区