滑块解锁(解决非人工操作提示)
最近接手一个自动化项目,登录页面有滑块解锁的验证,本来已经实现了滑块的滑动操作,但是总提示非人工操作,综合各种解决方案,最终实现方式如下:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/77217e78f05b7bf01343bfbbc99eeb86.png)
# coding = utf-8
import base64
import time
import cv2
import numpy as np
import random
from selenium import webdriver
from selenium.webdriver import ChromeOptions, ActionChains
from selenium.webdriver.common.by import By
class loginTAMS(object):
def __init__(self):
options = ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])
# 创建webdriver对象
self.driver = webdriver.Chrome(options=options)
def get_distance(self, driver):
script = """
return document.getElementsByTagName("canvas")[0].toDataURL("image/png");
"""
# 执行 JS 代码并拿到图片 base64 数据
im_info = driver.execute_script(script) # 执行js文件得到带图片信息的图片数据
im_base64 = im_info.split(',')[1] # 拿到base64编码的图片信息
im_bytes = base64.b64decode(im_base64) # 转为bytes类型
with open('target.png', 'wb') as f: # 保存图片到本地
f.write(im_bytes)
script = """
return document.getElementsByTagName("canvas")[1].toDataURL("image/png");
"""
# 执行 JS 代码并拿到图片 base64 数据
im_info = driver.execute_script(script) # 执行js文件得到带图片信息的图片数据
im_base64 = im_info.split(',')[1] # 拿到base64编码的图片信息
im_bytes = base64.b64decode(im_base64) # 转为bytes类型
with open('target2.png', 'wb') as f: # 保存图片到本地
f.write(im_bytes)
# 使用opencv读取两张图片
simg = cv2.imread('target2.png')
bimg = cv2.imread('target.png')
# 灰度处理,降低偏差
s_img = cv2.cvtColor(simg, cv2.COLOR_BGR2GRAY)
b_img = cv2.cvtColor(bimg, cv2.COLOR_BGR2GRAY)
# 保存两张灰度处理的图片
cv2.imwrite('hui_simg.png', s_img)
cv2.imwrite('hui_bimg.png', b_img)
# 处理滑块图片,保存有效部分
s_img = s_img[s_img.any(1)]
# opencv的匹配算法,匹配模块寻找两张图片的相似之处
result = cv2.matchTemplate(b_img, s_img, cv2.TM_CCOEFF_NORMED)
# 获取坐标
# 获取最大索引
index_max = np.argmax(result)
# 获取到坐标
y, x = np.unravel_index(index_max, result.shape)
print("y:", y, "x:", x)
return x
def get_track(self, distance):
'''
拿到移动轨迹,模仿人的滑动行为,先匀加速后匀减速
:param self:
:param distance:需要移动的距离
:return: 存放每0.2秒移动的距离
'''
# 初速度
v = 0
# 单位时间为0.2s来统计轨迹,轨迹即0.2内的位移
t = 0.3
# 位移/轨迹列表,列表内的一个元素代表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(2, 5) # 加速运动
else:
a = -random.randint(2, 4) # 减速运动
# 初速度
v0 = v
# 0.2秒时间内的位移
s = v0*t+0.5*a*(t**2)
# 当前位置
current += s
# 添加到轨迹列表
tracks.append(round(s))
# 速度已经达到v,该速度作为下次的初速度
v = v0+a*t
# 反着滑动到大概准确位置
# for i in range(4):
# tracks.append(-random.randint(9, 10))
random.shuffle(tracks)
return tracks
def slide(self, tracks, webdriver):
slider = webdriver.find_element(By.XPATH, "//span[text()='向右滑']/preceding-sibling::div/div")
# 鼠标点击并按住不松
action = ActionChains(webdriver)
action.click_and_hold(slider).perform()
# 让鼠标随机往下移动一段距离
action.move_by_offset(xoffset=0, yoffset=100).perform()
time.sleep(0.15)
for item in tracks:
action.move_by_offset(xoffset=item, yoffset=random.randint(-2, 2)).perform()
# 稳定一秒再松开
time.sleep(1)
action.release()
action.perform()
time.sleep(1)
# 随机拿开鼠标
#action.move_by_offset(xoffset=random.randint(200, 300), yoffset=random.randint(200, 300)).perform()
time.sleep(0.2)
info = webdriver.find_element(By.XPATH, "//div[@id='slideVerify']/following-sibling::div")
if '验证通过' in info.text:
return 1
if '验证失败' in info.text:
return 2
def enterLoginInfo(self, url, userIdXpath, userid, passwordXpath, password):
self.driver.get(url)
self.driver.maximize_window()
time.sleep(2)
self.driver.find_element(By.XPATH, userIdXpath).send_keys(userid)
self.driver.find_element(By.XPATH, passwordXpath).send_keys(password)
def verifyCanvas(self, submitxpath):
while True:
distance = self.get_distance(self.driver)
tracks = self.get_track(distance)
returnValue = self.slide(tracks, self.driver)
if returnValue == 1:
break
self.driver.find_element(By.XPATH, submitxpath).click()
由于我用的自动化测试框架为robotframework,上述的方法需要浏览器的驱动操作,所以需要将上述方法放到seleniumlibrary文件的keywords下的element.py文件中,
def get_distance(self):
script = """
return document.getElementsByTagName("canvas")[0].toDataURL("image/png");
"""
# 执行 JS 代码并拿到图片 base64 数据
im_info = self.driver.execute_script(script) # 执行js文件得到带图片信息的图片数据
im_base64 = im_info.split(',')[1] # 拿到base64编码的图片信息
im_bytes = base64.b64decode(im_base64) # 转为bytes类型
with open('target.png', 'wb') as f: # 保存图片到本地
f.write(im_bytes)
script = """
return document.getElementsByTagName("canvas")[1].toDataURL("image/png");
"""
# 执行 JS 代码并拿到图片 base64 数据
im_info = self.driver.execute_script(script) # 执行js文件得到带图片信息的图片数据
im_base64 = im_info.split(',')[1] # 拿到base64编码的图片信息
im_bytes = base64.b64decode(im_base64) # 转为bytes类型
with open('target2.png', 'wb') as f: # 保存图片到本地
f.write(im_bytes)
# 使用opencv读取两张图片
simg = cv2.imread('target2.png')
bimg = cv2.imread('target.png')
# 灰度处理,降低偏差
s_img = cv2.cvtColor(simg, cv2.COLOR_BGR2GRAY)
b_img = cv2.cvtColor(bimg, cv2.COLOR_BGR2GRAY)
# 保存两张灰度处理的图片
cv2.imwrite('hui_simg.png', s_img)
cv2.imwrite('hui_bimg.png', b_img)
# 处理滑块图片,保存有效部分
s_img = s_img[s_img.any(1)]
# opencv的匹配算法,匹配模块寻找两张图片的相似之处
result = cv2.matchTemplate(b_img, s_img, cv2.TM_CCOEFF_NORMED)
# 获取坐标
# 获取最大索引
index_max = np.argmax(result)
# 获取到坐标
y, x = np.unravel_index(index_max, result.shape)
print("y:", y, "x:", x)
return x+10
def get_track(self, distance):
'''
拿到移动轨迹,模仿人的滑动行为,先匀加速后匀减速
:param self:
:param distance:需要移动的距离
:return: 存放每0.2秒移动的距离
'''
# 初速度
v = 0
# 单位时间为0.2s来统计轨迹,轨迹即0.2内的位移
t = 0.3
# 位移/轨迹列表,列表内的一个元素代表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(2, 5) # 加速运动
else:
a = -random.randint(2, 4) # 减速运动
# 初速度
v0 = v
# 0.2秒时间内的位移
s = v0 * t + 0.5 * a * (t ** 2)
# 当前位置
current += s
# 添加到轨迹列表
tracks.append(round(s))
# 速度已经达到v,该速度作为下次的初速度
v = v0 + a * t
# 反着滑动到大概准确位置
# for i in range(4):
# tracks.append(-random.randint(9, 10))
random.shuffle(tracks)
return tracks
def slide(self, tracks, sliderXpath, checkXpath):
slider = self.driver.find_element(By.XPATH, sliderXpath)
# 鼠标点击并按住不松
action = ActionChains(self.driver)
action.click_and_hold(slider).perform()
# 让鼠标随机往下移动一段距离
action.move_by_offset(xoffset=0, yoffset=100).perform()
time.sleep(0.15)
for item in tracks:
action.move_by_offset(xoffset=item, yoffset=random.randint(-2, 2)).perform()
# 稳定一秒再松开
time.sleep(1)
action.release()
action.perform()
time.sleep(1)
# 随机拿开鼠标
# action.move_by_offset(xoffset=random.randint(200, 300), yoffset=random.randint(200, 300)).perform()
time.sleep(0.2)
info = self.driver.find_element(By.XPATH, checkXpath)
if '验证通过' in info.text:
return 1
if '验证失败' in info.text:
return 2
然后在robotframework中直接调用verifyCanvas方法即可。