今日头条 - 滑块登陆
今日头条不管怎样都绕不开滑块验证。那就开干吧。
难点
滑块登陆具体如何实现,看了很多博客,其实最重要的就两点:
- 背景图片和缺口之间的距离
- 模拟人滑动
计算间距
能够获得完整图片
有关背景图片和缺口之间的距离计算,有些网页上能够获得完整的背景图,因此可以使用的方式是:找到完整背景图和缺口背景图,两图的像素进行对比,找到边缘与缺口最左侧的距离。具体可参考 夜斗小神社
无法获得完整图片
但有些网站是没有完整图片的。这个时候就只能通过缺口背景图和缺口图进行比对,找到两图之间的距离。常用方法是cv2.matchTemplate。因此要着重看一下cv2.matchTemplate是如何实现的。
cv2.matchTemplate
cv2.matchTemplate 的原理就是将缺口从上至下,从左至右的与模板图片进行比对,看重合的图片相似度有多高【以左上角像素点为单位,获取与缺口图相同大小的图像,进行像素比较】,返回结果矩阵。 然后通过cv2.minMaxLoc获取到矩阵中最大和最小值和对应坐标。 坐标的x轴就是我们要计算得到的距离。
计算间距的具体流程
- 读取当前灰度图片
- cv2.matchTemplate获取结果矩阵
- cv2.minMaxLoc获取最大值坐标
- 等比缩放
前三步最终结果返回是300,而自己手动测量是295,差别不大但有点好奇,就拿rectangle圈了一下测试的位置,结果!!!
哦豁,位置找错了,看来要提高结果的精度
消除图像噪声
cv2.GaussianBlur - 通过平均像素值和相邻像素的值来平滑图像,消除噪声。
"""读取图片"""
blockJpg = cv2.imread(blockJpg, 0)
templateJpg = cv2.imread(templateJpg, 0)
def _tran_canny(image):
"""消除噪声"""
image = cv2.GaussianBlur(image, (3, 3), 0)
return cv2.Canny(image, 50, 150)
"""模式匹配"""
res = cv2.matchTemplate(_tran_canny(blockJpg), _tran_canny(templateJpg), cv2.TM_CCOEFF_NORMED)
"""获取最大最小值"""
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
最终能够正常圈出结果
然后还剩最后一步:等比缩放。因为获取到的是原图,但实际上网页中的图片进行了等比缩放,如果按照原图距离移动肯定匹配不上
模拟滑动
模拟滑动其实就是模仿人的常识性动作。一般而言人在滑动过程中会经历 慢-快-慢 的过程 - 加速度。所以对整个路径分为5部分
- 首次点击 - 停顿一秒
- 前1/5的距离稍微慢点的加速滑动
- 中间3/5的距离快速滑动
- 最后1/5的距离减速滑动
- 校准时停顿0.7s再松开
路径计算
def get_tracks(self, distance):
# 初始速度
v = 0
# 单位时间 0.2s内 统计轨迹
m = 0.3
# 每0.2s的轨迹列表
tracks = []
# 当前位置
current = 0
# 从减速到加速的位置
# font = distance * 1/5
# 从加速到减速的位置
mid = distance*4/5
while current <= distance:
if current < font:
# 减速
a = -1
if current < mid:
# 加速
a = 2
else:
# 减速
a = -3
v0 = v
# x = v0*t + 1/2^2
s = v0*m+0.5*a*(m**2)
current += s
tracks.append(round(s))
v = v0+a*m
return tracks
滑动
- 点击不松开
- 滑动
- 松开
# 获取每隔0.2秒的位置
tracks = self.get_tracks(gap)
print(gap)
# 定位按钮滑块的位置
element = wait.until(EC.presence_of_element_located((By.XPATH,'//div[@class="secsdk-captcha-drag-icon sc-kEYyzF fiQtnm"]')))
ActionChains(browser).click_and_hold(on_element=element).perform()
# 先停顿1s
time.sleep(1)
# 每0.3s改变一下当前需要移动的距离
for track in tracks:
# x拖动的位置,y拖动的位置
ActionChains(browser).move_by_offset(xoffset=track, yoffset=0).perform()
# 等一下再松开
time.sleep(0.5)
ActionChains(browser).release(on_element=element).perform()
然而还是被检测出来了
转载自:https://juejin.cn/post/7030821175429169189