文章目录
写在前面
最近学习了滑动验证的一个破解思路,是利用OpenCV的图形匹配算法进行对比验证,从而推算出滑块移动的距离,在实际应用中比较常见,我主要参考了Bilibili的教程:[案例篇] selenium+openCV干掉滑动验证码,里面的老师讲解的很详细,不过视频中提到的网易易盾网站做了一些调整,不过其大体思路是一样的,调整后的代码实现我放在下面了,供有需要的朋友学习研究。
大致思路
- 检查元素,观察网页结构,发现需要进行两次点击才能够到达滑动验证界面,其中的Xpath路径直接复制即可得到。
- 提取待分析(匹配)的两张图片的链接,利用
requests.get()方法直接保存图片到本地。 - 用
cv2库的imread()导入图片,进行灰度处理(使之变为单一图层)及空白去除。 - 利用图像匹配算法计算匹配精度最高的点(滑块图片的左上角点)的坐标。
- 利用
ActionChains设定距离拖放,即可完成验证。
Python实现
主要用到的库是:
selenium:进行网页的自动化控制,点击以及拖放(拖放需要用到ActionChains)requests:下载滑动验证中用到的图片,方便之后的分析cv2:进行两个图像灰度处理(提高效率)以及匹配
import cv2 as cv
import requests
import numpy as np
from time import sleep
from selenium.webdriver import Edge
from selenium.webdriver.common.action_chains import ActionChains
def save_fig(web):
slide_url = web.find_element_by_xpath(
'/html/body/main/div[1]/div/div[2]/div[2]/div[1]/div[2]/div[1]/div/' \
'div[2]/div[3]/div/div/div[2]/div/div/div[1]/div/div[1]/img[2]'
).get_attribute('src')
slide = requests.get(slide_url).content
with open('slide.png', 'wb') as f1:
f1.write(slide)
bg_url = web.find_element_by_xpath(
'/html/body/main/div[1]/div/div[2]/div[2]/div[1]/div[2]/div[1]/div/' \
'div[2]/div[3]/div/div/div[2]/div/div/div[1]/div/div[1]/img[1]'
).get_attribute('src')
bg = requests.get(bg_url).content
with open('bg.jpg', 'wb') as f2:
f2.write(bg)
if __name__ == '__main__':
web = Edge(r"C:\msedgedriver.exe")
web.get("https://dun.163.com/trial/sense")
web.implicitly_wait(10)
# 进入滑块验证界面
web.find_element_by_xpath(
'/html/body/main/div[1]/div/div[2]/div[2]/ul/li[2]'
).click()
sleep(1)
web.find_element_by_xpath(
'/html/body/main/div[1]/div/div[2]/div[2]/div[1]/div[2]' \
'/div[1]/div/div[2]/div[3]/div/div/div[1]/div[1]/span'
).click()
sleep(1)
# 保存图片
save_fig(web)
# 使用OpenCV导入图片为RGB矩阵格式
bg = cv.imread('bg.jpg')
slide = cv.imread('slide.png')
# 利用openCV进行灰度处理
bg = cv.cvtColor(bg, cv.COLOR_BGR2GRAY)
slide = cv.cvtColor(slide, cv.COLOR_BGR2GRAY)
# 处理滑块,去掉空白部分
# 即对图像矩阵进行处理,去掉图像矩阵中值为0的部分(空白)
slide = slide[slide.any(1)]
# 进行图形匹配,使用精度最高的算法(速度较慢)
result = cv.matchTemplate(bg, slide, method=cv.TM_CCOEFF_NORMED)
# 提取匹配到的图像左上角坐标
# 注意这里x表示纵坐标,y表示横坐标
# `np.argmax`得到一维情形下的最大值,需要转化成二维
x, y = np.unravel_index(np.argmax(result), result.shape)
# 定位滑块位置
web_slide = web.find_element_by_xpath(
'/html/body/main/div[1]/div/div[2]/div[2]/div[1]/div[2]/div[1]' \
'/div/div[2]/div[3]/div/div/div[2]/div/div/div[2]/div[2]'
)
# 进行拖放操作
# 注意横向移动距离整除1.01
# 因为原始图片在网页中进行了一定比例的缩放
ActionChains(web).drag_and_drop_by_offset(
web_slide, xoffset=y/1.01, yoffset=0
).perform()
几个小坑
- 要注意
OpenCV中的图像宽高分别对应矩阵的列数与行数,所以得到的坐标中x与y是反的。 - 要注意
ActionChians中的拖动距离,需要除以一个略大于1的数,因为网页中的图片经过CSS样式调整,有了一定比例的缩放。但是我发现在拖动距离未达到背景图宽度的一半时不设置缩放也可以验证成功。 OpenCV的图像匹配算法不能保证每次都验证成功,实际运用中需要多次验证。- 有的网站可能会设置机器识别,即如果只是使用
selenium的匀速拖放,可能会被识别为机器,此时可以设置拖放速度,使得其拖放行为与人的操作更加相似。