用selenium解决滑块验证码的实现步骤

 更新时间:2023年02月14日 10:06:02   作者:骑着青蛙一起二  
验证码作为一种自然人的机器人的判别工具,被广泛的用于各种防止程序做自动化的场景中,下面这篇文章主要给大家介绍了关于用selenium解决滑块验证码的实现步骤,需要的朋友可以参考下

前言

因为种种原因没能实现愿景的目标,在这里记录一下中间结果,也算是一个收场吧。这篇博客主要是用selenium解决滑块验证码的个别案列。

思路:

  • 用selenium打开浏览器指定网站
  • 将残缺块图片和背景图片下载到本地
  • 对比两张图片的相似地方,计算要滑动的距离
  • 规划路线,移动滑块

实现步骤

1. 用selenium打开浏览器浏览指定网站

1.1 找到chromedriver.exe的路径

点击开始找到谷歌图标==》右键更多==》打开文件位置==》右键谷歌快捷方式==》属性 ==》打开文件所在的位置 ==》复制路径

chromedriver.exe路径

1.2 代码

from selenium import webdriver
# chrome_path要改成你自己的路径
chrome_path = r"C:\Users\11248\AppData\Local\Google\Chrome\Application\chromedriver.exe"
url = 'https://icas.jnu.edu.cn/cas/login'
driver = webdriver.Chrome(chrome_path)
driver.get(url)

2.将残缺块图片和背景图片下载到本地

2.1 找到图片位置

打开网页进入开发者工具,找到图片位置

2.2 代码

import time
import requests
from PIL import Image
from selenium.webdriver.common.by import By
from io import BytesIO

time.sleep(5)	# 进入页面要停留几秒钟,等页面加载完
target_link = driver.find_element(By.CLASS_NAME, "yidun_bg-img").get_attribute('src')
template_link = driver.find_element(By.CLASS_NAME, "yidun_jigsaw").get_attribute('src')

target_img = Image.open(BytesIO(requests.get(target_link).content))
template_img = Image.open(BytesIO(requests.get(template_link).content))
target_img.save('target.jpg')
template_img.save('template.png')

3. 对比两张图片的相似地方,计算要滑动的距离

3.1 用matchTemplate获取移动距离

因为背景图片中的残缺块位置和原始残缺图的亮度有所差异,直接对比两张图片相似的地方,往往得不到令人满意的结果,在此要对两张图片进行一定的处理,为了避免这种亮度的干扰,笔者这里将两张图片先进行灰度处理,再对图像进行高斯处理,最后进行边缘检测。

def handel_img(img):
    imgGray = cv2.cvtColor(img, cv2.COLOR_RGBA2GRAY)  # 转灰度图
    imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1)  # 高斯模糊
    imgCanny = cv2.Canny(imgBlur, 60, 60)  # Canny算子边缘检测
    return imgCanny

为增加工作量(放屁,统一代码好看点) 将JPG图像转变为4通道(RGBA)

def add_alpha_channel(img):
    """ 为jpg图像添加alpha通道 """
    r_channel, g_channel, b_channel = cv2.split(img)  # 剥离jpg图像通道
    alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255  # 创建Alpha通道
    img_new = cv2.merge((r_channel, g_channel, b_channel, alpha_channel))  # 融合通道
    return img_new

3.2 代码

import cv2
# 读取图像
def match(img_jpg_path, img_png_path):
    # 读取图像
    img_jpg = cv2.imread(img_jpg_path, cv2.IMREAD_UNCHANGED)
    img_png = cv2.imread(img_png_path, cv2.IMREAD_UNCHANGED)
    # 判断jpg图像是否已经为4通道
    if img_jpg.shape[2] == 3:
        img_jpg = add_alpha_channel(img_jpg)
    img = handel_img(img_jpg)
    small_img = handel_img(img_png)
    res_TM_CCOEFF_NORMED = cv2.matchTemplate(img, small_img, 3)
    value = cv2.minMaxLoc(res_TM_CCOEFF_NORMED)
    value = value[3][0]  # 获取到移动距离
    return value

3.3 检验效果

为了验证思路和方法是否得当,这里将滑块图片与背景图片进行拼接,为后面埋下一个小坑。

def merge_img(jpg_img, png_img, y1, y2, x1, x2):
    """ 将png透明图像与jpg图像叠加
        y1,y2,x1,x2为叠加位置坐标值
    """
    # 判断jpg图像是否已经为4通道
    if jpg_img.shape[2] == 3:
        jpg_img = add_alpha_channel(jpg_img)
    # 获取要覆盖图像的alpha值,将像素值除以255,使值保持在0-1之间
    alpha_png = png_img[yy1:yy2, xx1:xx2, 3] / 255.0
    alpha_jpg = 1 - alpha_png

    # 开始叠加
    for c in range(0, 3):
        jpg_img[y1:y2, x1:x2, c] = ((alpha_jpg * jpg_img[y1:y2, x1:x2, c]) + (alpha_png * png_img[yy1:yy2, xx1:xx2, c]))

    return jpg_img
    
img_jpg_path = 'target.jpg'  # 读者可自行修改文件路径
img_png_path = 'template.png'  # 读者可自行修改文件路径
x1 = match(img_jpg_path, img_png_path)
y1 = 0
x2 = x1 + img_png.shape[1]
y2 = y1 + img_png.shape[0]
# 开始叠加
res_img = merge_img(img_jpg, img_png, y1, y2, x1, x2)
cv2.imshow("res_img ", res_img)
cv2.waitKey(0)

4. 规划路线,移动滑块

4.1 点击滑块移动

用第3节已经获取到的距离,点击滑块进行移动

from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver import ActionChains

def crack_slider(distance):
	wait = WebDriverWait(driver, 20)
    slider = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'yidun_slider')))
    ActionChains(self.driver).click_and_hold(slider).perform()
    ActionChains(self.driver).move_by_offset(xoffset=distance, yoffset=0).perform()
    time.sleep(2)
    ActionChains(self.driver).release().perform()
    return 0

神奇的事情是,坑来了,没有匹配成功。

4.2 匹配失败原因

这里有以下两点原因:

  • 图片尺寸发生了变化,距离要进行转换。
  • 滑块滑动时,滑块和残缺块的相对位置有变动

首先解决图片尺寸变化问题,找到网页中图片大小:345x172.500

下载到本地图片大小:480x240

本地背景尺寸大小

所以要对距离进行以下处理:

	distance = distance / 480 * 345

关于第二个问题,这里没有找到很好的测量工具测量出来,好在验证码对位置精确度要求不高,就一个个试数吧。

distance = distance /480 * 345 + 12

5 运行演示

success

补充

在对极验验证码进行学习中,有的网站对移动轨迹进行了验证,如果滑动太快,也会被识别出机器操作,为了模拟人工操作,出色的程序员写出了一个魔幻移动轨迹,举个例子:我们可以先超过目标,再往回移动。

 def get_tracks(distance):
     distance += 20
     v = 0
     t = 0.2
     forward_tracks = []
     current = 0
     mid = distance * 3 / 5
     while current < distance:
         if current < mid:
             a = 2
         else:
             a = -3
         s = v * t + 0.5 * a * (t ** 2)
         v = v + a * t
         current += s
         forward_tracks.append(round(s))

     back_tracks = [-3, -3, -2, -2, -2, -2, -2, -1, -1, -1]
     return {'forward_tracks': forward_tracks, 'back_tracks': back_tracks}

  def crack_slider(tracks):
  	  wait = WebDriverWait(driver, 20)
      slider = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'yidun_slider')))
      ActionChains(driver).click_and_hold(slider).perform() # 模拟按住鼠标左键

      for track in tracks['forward_tracks']:
          ActionChains(driver).move_by_offset(xoffset=track, yoffset=0).perform()

      time.sleep(0.5)
      for back_tracks in tracks['back_tracks']:
          ActionChains(driver).move_by_offset(xoffset=back_tracks, yoffset=0).perform()

      ActionChains(driver).move_by_offset(xoffset=-4, yoffset=0).perform()
      ActionChains(driver).move_by_offset(xoffset=4, yoffset=0).perform()
      time.sleep(0.5)

      ActionChains(driver).release().perform()	# 释放左键
      return 0

完整代码

# coding=utf-8
import re
import requests
import time
from io import BytesIO

import cv2
import numpy as np
from PIL import Image
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

class CrackSlider():
    # 通过浏览器截图,识别验证码中缺口位置,获取需要滑动距离,并破解滑动验证码

    def __init__(self):
        super(CrackSlider, self).__init__()
        self.opts = webdriver.ChromeOptions()
        self.opts.add_experimental_option('excludeSwitches', ['enable-logging'])
        # self.driver = webdriver.Chrome(ChromeDriverManager().install(), options=self.opts)
        chrome_path = r"C:\Users\11248\AppData\Local\Google\Chrome\Application\chromedriver.exe"
        self.driver = webdriver.Chrome(chrome_path, options=self.opts)

        self.url = 'https://icas.jnu.edu.cn/cas/login'
        self.wait = WebDriverWait(self.driver, 10)

    def get_pic(self):
        self.driver.get(self.url)
        time.sleep(5)
        target_link = self.driver.find_element(By.CLASS_NAME, "yidun_bg-img").get_attribute('src')
        template_link = self.driver.find_element(By.CLASS_NAME, "yidun_jigsaw").get_attribute('src')

        target_img = Image.open(BytesIO(requests.get(target_link).content))
        template_img = Image.open(BytesIO(requests.get(template_link).content))
        target_img.save('target.jpg')
        template_img.save('template.png')

    def crack_slider(self, distance):
        slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'yidun_slider')))
        ActionChains(self.driver).click_and_hold(slider).perform()
        ActionChains(self.driver).move_by_offset(xoffset=distance, yoffset=0).perform()
        time.sleep(2)
        ActionChains(self.driver).release().perform()
        return 0

def add_alpha_channel(img):
    """ 为jpg图像添加alpha通道 """

    r_channel, g_channel, b_channel = cv2.split(img)  # 剥离jpg图像通道
    alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255  # 创建Alpha通道

    img_new = cv2.merge((r_channel, g_channel, b_channel, alpha_channel))  # 融合通道
    return img_new

def handel_img(img):
    imgGray = cv2.cvtColor(img, cv2.COLOR_RGBA2GRAY)  # 转灰度图
    imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1)  # 高斯模糊
    imgCanny = cv2.Canny(imgBlur, 60, 60)  # Canny算子边缘检测
    return imgCanny

def match(img_jpg_path, img_png_path):
    # 读取图像
    img_jpg = cv2.imread(img_jpg_path, cv2.IMREAD_UNCHANGED)
    img_png = cv2.imread(img_png_path, cv2.IMREAD_UNCHANGED)
    # 判断jpg图像是否已经为4通道
    if img_jpg.shape[2] == 3:
        img_jpg = add_alpha_channel(img_jpg)
    img = handel_img(img_jpg)
    small_img = handel_img(img_png)
    res_TM_CCOEFF_NORMED = cv2.matchTemplate(img, small_img, 3)
    value = cv2.minMaxLoc(res_TM_CCOEFF_NORMED)
    value = value[3][0]  # 获取到移动距离
    return value

# 1. 打开chromedriver,试试下载图片
cs = CrackSlider()
cs.get_pic()
# 2. 对比图片,计算距离
img_jpg_path = 'target.jpg'  # 读者可自行修改文件路径
img_png_path = 'template.png'  # 读者可自行修改文件路径
distance = match(img_jpg_path, img_png_path)
distance = distance /480 * 345 + 12
# 3. 移动
cs.crack_slider(distance)

总结

到此这篇关于用selenium解决滑块验证码的文章就介绍到这了,更多相关selenium滑块验证码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Django使用Celery异步任务队列的使用

    Django使用Celery异步任务队列的使用

    这篇文章主要介绍了Django使用Celery异步任务队列的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • Python绘制直方图的示例代码

    Python绘制直方图的示例代码

    本文主要介绍了如何使用Python绘制直方图,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Python生成器(Generator)详解

    Python生成器(Generator)详解

    这篇文章主要介绍了Python生成器(Generator)详解,本文讲解了什么是生成器、简单生成器、带yield 语句的生成器、加强的生成器等内容,需要的朋友可以参考下
    2015-04-04
  • Python 编程操作连载之字符串,列表,字典和集合处理

    Python 编程操作连载之字符串,列表,字典和集合处理

    这篇文章主要介绍了Python 编程操作连载之字符串,列表,字典和集合处理,文章围绕主题相关资料展开详细的内容介绍,需要的朋友可参考一下下面文章内容
    2022-06-06
  • Python 3.11.0下载安装并使用help查看模块信息的方法

    Python 3.11.0下载安装并使用help查看模块信息的方法

    本文给大家介绍Python 3.11.0下载安装并使用help查看模块信息的相关知识,首先给大家讲解了Python 3.11.0下载及安装紧接着介绍了在命令行使用help查看模块信息的方法,感兴趣的朋友跟随小编一起看看吧
    2022-11-11
  • Python做个自定义动态壁纸还可以放视频

    Python做个自定义动态壁纸还可以放视频

    这篇文章主要介绍了如何用Python做个可以放视频自定义动态壁纸,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08
  • 解决pip install中UnicodeDecodeError问题的处理

    解决pip install中UnicodeDecodeError问题的处理

    这篇文章主要介绍了解决pip install中UnicodeDecodeError问题的处理,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-09-09
  • 深入了解和应用Python 装饰器 @decorator

    深入了解和应用Python 装饰器 @decorator

    在编程过程中,经常遇到这样的场景:登录校验,权限校验,日志记录等,这些功能代码在各个环节都可能需要,但又十分雷同,通过装饰器来抽象、剥离这部分代码可以很好解决这类场景,这篇文章主要介绍了Python的装饰器 @decorator,探讨了使用的方式,需要的朋友可以参考下
    2019-04-04
  • python对网页文本的格式化实例方法

    python对网页文本的格式化实例方法

    在本篇文章里小编给大家整理是一篇关于python对网页文本的格式化实例方法,有兴趣的朋友们可以跟着学习参考下。
    2021-10-10
  • python打开使用的方法

    python打开使用的方法

    在本篇文章里小编给各位整理的是关于python怎么打开使用的相关知识点内容,有需要的朋友们可以学习下。
    2019-09-09

最新评论