一、图片滑块验证问题
这里我以头条的登录界面举例子,其他的类似这种都是大同小异。修改关键代码就可以了
入口连接:https://ad.oceanengine.com/pages/login/index.html
二、解决思路
1.分析页面拿到背景图
2.计算滑块所需要的距离,即缺口位置
3.计算滑动轨迹
4.进行滑动
分析页面取出背景图
核心代码:
# 获取全背景图,进行裁剪保存
img = browser.find_element_by_xpath('//*[@id="validate-big"]')
location = img.location
print("location: ", location)
size = img.size
print("验证码大小:", size)
left, up, right, down = location["x"], location["y"], location["x"] + size["width"], location["y"] + size[
"height"]
print("截取后的图片信息:", left, up, right, down)
# 保存大背景图
browser.save_screenshot("toutiao.png")
# 截取小验证图
need_bg_img = Image.open("toutiao.png")
img_writer = need_bg_img.crop((left, up, right, down)) # 指定上下左右截取
img_writer.save("captcha.png")
通过selenium中xpath方法找到背景图,并且通过方法location和size确定图片的位置和大小,这已不是为了找到背景图位置,通过使用Pillow包将背景图截取出来,用来做之后的灰度化处理
计算滑块所需要的距离
先展示一下目标结果:
说明:左边的滑块y轴距离是不确定的,但是x轴是确定的,所以可以直接拿到x距离。然后右边是不固定的,可以通过对图像进行降噪或者边缘处理,由于技术问题,我直接进行变为灰度值,发现也还可以弄,获取到所有灰度值为255的,根据出现的y坐标频率最高的以及数值最大的判断得出缺口的x坐标,即缺口距离y轴距离。
核心代码:
# 转成灰度图进行处理
img = cv2.imread("captcha.png", 0) # 由于Canny只能处理灰度图,所以将读取的图像转成灰度图
img = cv2.GaussianBlur(img, (3, 3), 0) # 用高斯平滑处理原图像降噪。若效果不好可调节高斯核大小
canny = cv2.Canny(img, 200, 600) # 调用Canny函数,指定最大和最小阈值,其中apertureSize默认为3。
# cv2.imshow('Canny', canny)
# cv2.waitKey(1)
# 获取图片大小
x_len, y_len = canny.shape
# 遍历每个像素获取到 X 值,进行统计
x_arr = []
for i in range(1, x_len):
for j in range(1, y_len):
if canny[i, j] == 255.:
x_arr.append(j)
print("顺序打印看一下:", x_arr)
# 根据频率统计得到缺口距离y轴距离
former_dict = Counter(x_arr).most_common(5)
far_distance = max(dict(former_dict).keys())
distance = far_distance - 52
print(distance)
计算滑块轨迹
说明:为了不让头条识别出我们是机器滑动,所以我们可以采用之前学过的加速度原理,改变他的偏移量,让他速度忽快忽慢,和人的操作类似。
def get_track(distance): # 人为滑动是先慢 中快 后慢
"""
根据偏移量获取移动轨迹
:param distance: 偏移量
:return: 移动轨迹列表
"""
track = []
current = 0 # 当前位移
mid = distance * 4 / 5 # 设定一个阈值进行改变加速度
t = 1 # 计算间隔
v = 0 # 初速度
while current < distance:
if current < mid:
a = 1 # 加速度为正1
else:
a = -2 # 加速度为负2
v0 = v # 初速度v0
v = v0 + a * t # 当前速度v = v0 + at
# 移动距离x = v0t + 1/2 * a * t^2
move = v0 * t + 1 / 2 * a * t * t
current += move # 当前位移
track.append(round(move)) # 加入轨迹
track.append(distance-sum(track))
return track
学过的物理加速度公式此刻是不是觉得有了用武之地!我上面设置的是先慢、中快、后慢。这个小伙伴们可以自己设置,只要不要一下子让机器‘顺利’的划过去就好。
最后就是滑动
说明:最后一步比较简单直接上代码
dis_list = get_track(distance)
print(dis_list[1:])
print(sum(dis_list))
button = browser.find_element_by_xpath('//*[@id="validate-drag-wrapper"]/div[2]/img')
ActionChains(browser).click_and_hold(button).perform()
for dis in dis_list:
ActionChains(browser).move_by_offset(xoffset=dis, yoffset=0).perform()
ActionChains(browser).release().perform()
time.sleep(0.3)
总结:其实看了思路之后很简单,无非就是进入页面通过xpath找到滑块的位置,然后进行截图保存,之后通过高斯平滑进行降噪,将图片进行灰度化。这样是为了很好的找到缺口位置。网上也有比较RGB 的解决方案,个人觉得这个滑块没有必要。最后一步就是充分利用所学的物理知识进行模拟人的操作轨迹,自定义开始和结尾的速度。
会使用到的包:selenium+cv2+PIL就可以搞定
如果觉得有帮助到大家的可以帮忙点个关注,点个赞!想要源码的(已经测试成功的)可以加博主的微信私聊!