Selenium实现滑动验证学习

实现滑块验证,是通过selenium操作游览器,将滑动验证的原始图片和缺口图片进行对比,找出缺口位置,然后在利用selenium模拟拖动滑块,达到验证的目的。

这里以知乎知乎为例:(https://www.zhihu.com)

image20251120193219982

首先通过selenium的定位方法实现登录操作(点击密码登录–>输入账号密码–>点击登录–>滑块验证)

selenium的定位方法有:

1、通过ID定位:使用元素的ID属性

1
driver.find_element(By.ID,"ID_value")#ID必须是唯一的,这样才能找的准确

2、通过NAME定位:使用元素的name属性

1
driver.find_element(By.NAME,"name_value")

3、通过CLASS_NAME定位:使用元素的class属性(注意:只能使用单个类名,多个类名需要用其他方法)。

1
driver.find_element(By.CLASS_NAME, "class_name")

4、通过TAG_NAME定位:使用元素的标签名

1
driver.find_element(By.TAG_NAME, "tag_name")

5、通过LINK_TEXT定位:用于链接元素,通过链接的完整文本。

1
driver.find_element(By.LINK_TEXT, "link_text")

6、通过PARTIAL_LINK_TEXT定位:用于链接元素,通过链接的部分文本。

1
driver.find_element(By.PARTIAL_LINK_TEXT, "partial_link_text")

7、通过CSS_SELECTOR定位:使用CSS选择器,功能强大,支持多种复杂情况

1
driver.find_element(By.CSS_SELECTOR, "css_selector")

8、通过XPATH定位:使用XPath表达式,可以在整个文档中定位元素。

1
driver.find_element(By.XPATH, "xpath_expression")

定位策略建议

  1. 优先级推荐
    • 首选:ID(唯一且快速)
    • 次选:CSS Selector(性能好,语法简洁)
    • 再次:XPath(功能强大但稍慢)
    • 最后:其他方法
  2. 最佳实践
    • 尽量使用稳定的属性定位
    • 避免使用绝对XPath路径
    • 结合显式等待提高稳定性
    • 使用有意义的元素标识

在输入账号密码后,点击登录会弹出安全验证:

image20251120195033601

实现滑动验证,需要计算出滑块到图片缺口的距离,再通过selenium操作滑块按钮进行拉动到指定位置。

由于在游览器开发者模式中能够找到背景图片和滑动图片的链接

image20251120195317196

1
2
3
4
5
6
7
8
9
#通过XPATH方法,相对地址定位图片链接位置
bgImage = driver.find_element(By.XPATH,"//img[@alt='验证码背景']")
SldierImage = driver.find_element(By.XPATH,"//img[@alt='验证码滑块']")
#获取图片链接
ImageSrc = bgImage.get_attribute("src")
SldierImage_src = sldierImage.get_attribute("src")
#通过urllib库进行图片保存
urllib.request.urlretrieve(ImageSrc,'ImageSrc.png')
urllib.request.urlretrieve(SldierImage_src,'SldierImage_src.png')

所以这里我们主要使用了open CV的模板匹配:所谓模板匹配就是在一个图像中识别出与模板相似的区域。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#实现代码

def get_distance(sldier,backgroud):
#获取图片
sldier_img = cv2.imread(sldier)
bg_img = cv2.imread(backgroud)
#对图片进行预处理
sldier_gray = cv2.cvtColor(sldier_img,cv2.COLOR_BGRA2GRAY)#将图片转化为灰度图
bg_gray = cv2.cvtColor(bg_img,cv2.COLOR_BGRA2GRAY)
sldier_canny = cv2.Canny(sldier_gray,200,300)#对图片进行轮廓检测
bg_canny = cv2.Canny(bg_gray,200,300)
#使用cv2.matchTemplate函数进行模板匹配
restul = cv2.matchTemplate(sldier_canny,bg_canny,cv2.TM_CCOEFF_NORMED)
#min_val,max_val,min_loc,max_loc = cv2.minMaxLoc(restul)
#letf = max_loc
top,left = np.unravel_index(restul.argmax(),restul.shape)
return left

cv2.matchTemplate函数有四个参数:

1
cv2.matchTemplate(image, templ, method, mask) → result
  • image:原始图像。
  • templ:模板图像。
  • method:用来指定匹配算法,常见的有 6 种,包括:
    • cv2.TM_CCOEFF
    • cv2.TM_CCOEFF_NORMED
    • cv2.TM_CCORR
    • cv2.TM_CCORR_NORMED
    • cv2.TM_SQDIFF
    • cv2.TM_SQDIFF_NORMED
  • mask:可选参数,用来指定在源图像和模板图像上进行匹配的区域

image20251120201114717

返回值说明:

函数返回的结果result是一个矩阵,其大小取决于源图像和模板的相对大小。具体来说,如果源图像的大小是(W, H),模板的大小是(w, h),则结果矩阵的大小将是(W-w+1, H-h+1)。结果矩阵中的每个元素都表示模板在原图中对应位置的匹配程度,具体取决于所选的比较方法。

image20251120202552264

在模板匹配的过程中,模板会在原始图像中移动,并与重叠区域内的像素诸葛对比,最后将对比结果保存在模板左上角像素点索引位置对应的数组位置中。

image20251120213044

通过cv2.matchTemplate函数获取到缺口的位置(X,Y),这里的X就是要移动的距离,但是实际游览器上的图片大小和我们下载过来的图片大小有时候是有差异的,所以需要对X进行缩放处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
#获取游览器图片大小
bgImage = driver.find_element(By.XPATH,"//img[@alt='验证码背景']")
bg_width = bgImage.size["width"]
#获取下载图片的大小
real_width = cv2.imread('bgImage.png').shape[1]
#scale为缩放大小
scale = bg_width/real_width
#detal为滑块初始的位置距离,这里为10pix
detal =10
#获取移动距离
distance = get_distance('SldierImage.png','bgImage.png')
#计算真实距离
reality_dis = distance*scale +detal

最后通过操纵游览器进行移动:

1
2
3
4
5
6
7
8
9
10
11
12
def move_slider(distance,slider):
#点击和按住滑动按钮
ActionChains(driver).click_and_hold(slider).perform()
#移动距离
moved = 0
#未到指定位置之前随机移动3-10个像素
while moved<distance:
x =random.randint(3,10)
moved+=x
ActionChains(driver).move_by_offset(xoffset=x,yoffset=0).perform()
#松开鼠标左键
ActionChains(driver).release().perform()