Selenium实现滑动滑块验证码验证

背景:在部分的登录中有滑动验证码的验证,由于滑动验证码的缺块是随机的就导致实现起来比较困难!

先看结果

登录豆瓣

再看代码

class CrackSlider(object):
    """
    滑动验证码工具
    1、add_alpha_channel:为jpg图像添加alpha通道
    2、handel_img:灰度处理,再对图像进行高斯处理,最后进行边缘检
    3、match:获取到移动距离
    """

    def __add_alpha_channel(self, 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(self, 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(self, element, img1_path, img2_path, num1, num2):
        """
        模板匹配,通过openCV分析两个图片的相似度,获取两个相似度很高图片的坐标,从而计算两个图片的距离。
        传入 全图位置、缺口位置、浏览器图片宽度、本地图片宽度 获取到移动距离
        element:元素对象
        img_jpg_path:全图
        img_png_path:缺口
        num1:浏览器图片宽度
        num2:本地图片宽度
        """
        # 读取图像
        img1_path = cv2.imread(img1_path, cv2.IMREAD_UNCHANGED)
        img2_path = cv2.imread(img2_path, cv2.IMREAD_UNCHANGED)
        # 判断jpg图像是否已经为4通道
        if img1_path.shape[2] == 3:
            img1_path = self.__add_alpha_channel(img1_path)
        img = self.__handel_img(img1_path)
        small_img = self.__handel_img(img2_path)
        res_TM_CCOEFF_NORMED = cv2.matchTemplate(img, small_img, 3)
        value = cv2.minMaxLoc(res_TM_CCOEFF_NORMED)
        value = value[3][0]  # 获取到移动距离
        value = value * num1 / num2 - element.location['x']
        return value

    def get_pos(self, element, img1, num, num1, num2):
        """
        轮廓检测,通过openCV进行轮廓检测,即在大图片中找到缺口位置的坐标,然后计算小图片到缺口位置的距离。
        传入 图片、缺口像素、浏览器图片宽度、本地图片宽度 获取移动像素
        :param element: 元素位置
        :param imageSrc: 图片地址
        :param num: 图片缺口长宽像素,基本上长宽必须一致
        :param num1: 浏览器图片宽度
        :param num2: 本地图片宽度
        :return: 缺口x坐标
        """
        # 读取图像文件并返回一个image数组表示的图像对象
        image = cv2.imread(img1)
        # GaussianBlur方法进行图像模糊化/降噪操作。
        # 它基于高斯函数(也称为正态分布)创建一个卷积核(或称为滤波器),该卷积核应用于图像上的每个像素点。
        blurred = cv2.GaussianBlur(image, (5, 5), 0, 0)
        # Canny方法进行图像边缘检测
        # image: 输入的单通道灰度图像。
        # threshold1: 第一个阈值,用于边缘链接。一般设置为较小的值。
        # threshold2: 第二个阈值,用于边缘链接和强边缘的筛选。一般设置为较大的值
        canny = cv2.Canny(blurred, 0, 100)  # 轮廓
        # findContours方法用于检测图像中的轮廓,并返回一个包含所有检测到轮廓的列表。
        # contours(可选): 输出的轮廓列表。每个轮廓都表示为一个点集。
        # hierarchy(可选): 输出的轮廓层次结构信息。它描述了轮廓之间的关系,例如父子关系等。
        contours, hierarchy = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        # 遍历检测到的所有轮廓的列表
        for contour in contours:
            # contourArea方法用于计算轮廓的面积
            area = cv2.contourArea(contour)
            # arcLength方法用于计算轮廓的周长或弧长
            length = cv2.arcLength(contour, True)
            # 如果检测区域面积在原来基础上下百分之四之间,周长在原来基础上下百分之四之间,则是目标区域
            if num*num-num*num/4 < area < num*num+num*num/4 and num*4-num*4/4 < length < num*4+num*4/4:
                # 计算轮廓的边界矩形,得到坐标和宽高
                # x, y: 边界矩形左上角点的坐标。
                # w, h: 边界矩形的宽度和高度。
                x, y, w, h = cv2.boundingRect(contour)
                print("计算出目标区域的坐标及宽高:", x, y, w, h)
                # 在目标区域上画一个红框看看效果
                cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
                cv2.imwrite("img/test.jpg", image)
                return x * num1 / num2 - element.location['x']
        return 0

    def add_img1(self, img1):
        """
        将http图片保存到本地
        img1:全图url
        """
        urllib.request.urlretrieve(img1, 'img/img1.jpg')

    def add_img2(self, img1, img2):
        """
        将http图片保存到本地
        img1:全图url
        img2:缺口url
        """
        urllib.request.urlretrieve(img1, 'img/img1.jpg')
        urllib.request.urlretrieve(img2, 'img/img2.jpg')

    def slowly(self, driver, element, Dis):
        """
        慢慢滑动滑块模拟人的操作,一次次移动一点点
        传入 浏览器对象、元素位置、移动距离 实现移动滑块
        :param driver: 浏览器对象
        :param element: 元素位置
        :param Dis: 移动距离
        :return:
        """
        ActionChains(driver).click_and_hold(element).perform()
        # 移动小滑块,模拟人的操作,一次次移动一点点
        i = 0
        moved = 0
        while moved < Dis:
            x = random.randint(3, 10)  # 每次移动3到10像素
            moved += x
            ActionChains(driver).move_by_offset(xoffset=x, yoffset=0).perform()
            print("第{}次移动后,位置为{}".format(i, element.location['x']))
            i += 1
        # 移动完之后,松开鼠标
        ActionChains(driver).release().perform()

1、实现方案

1、模板匹配,通过openCV分析两个图片的相似度,获取两个相似度很高图片的坐标,从而计算两个图片的距离。

2、轮廓检测,通过openCV进行轮廓检测,即在大图片中找到缺口位置的坐标,然后计算小图片到缺口位置的距离。

2、知识准备

2.1、python语言

这里不再赘述,本篇主要还是使用python技术来实现。

2.2、selenium库

selenium是一个用于测试Web应用程序的Python库。它可以模拟用户在浏览器中的操作,例如点击、填写表单等。Selenium可以与各种浏览器交互,并提供了丰富的API来控制浏览器行为和获取网页内容。

2.3、urllib库

urllib是Python标准库之一,用于处理URL相关的操作。它包含多个子模块,例如urllib.request用于发送HTTP请求并获取响应,urllib.parse用于解析和构建URL,urllib.error用于处理URL相关的错误等。urllib常用于网络数据抓取、访问API等任务。

2.4、cv2库

cv2是OpenCV(Open Source Computer Vision)库的Python绑定。OpenCV是一个广泛使用的计算机视觉库,提供了丰富的图像处理和计算机视觉算法。cv2库为Python开发者提供了对OpenCV功能的访问,可以进行图像加载、处理、分析以及计算机视觉任务,如人脸识别、目标检测等。
安装注意事项:
如果直接通过pip install cv2安装报错的话,请使用下面的语句安装:
pip install opencv-python

2.5、random库

random是Python的随机数生成库。它提供了多种随机数生成函数,包括生成伪随机数的函数和从序列中随机选择元素的函数。random库可用于模拟、游戏开发、密码学等领域,以及各种需要随机性的应用程序。

2.6、re库

re是Python的正则表达式模块,用于对字符串进行模式匹配和处理。正则表达式是一种强大的文本匹配工具,可以用来搜索、替换、提取特定模式的字符串。re库提供了函数和方法来编译正则表达式、执行匹配操作,并返回匹配结果,使得处理文本数据更加灵活和高效

2.7、time库

的time库是处理时间的标准库,提供了获取系统时间、格式化输出、系统级精确计时等功能。

3、实现步骤

3.1、打开登录页切换密码登录

第一步,打开登录页面,并点击页面上的“密码登录”:

代码:

driver = webdriver.Edge()  # 实例化驱动对象
driver.maximize_window()  # 窗口最大化
driver.get("https://accounts.douban.com/passport/login")  # 打开豆瓣登录页面
driver.implicitly_wait(5)  # 隐式等待5秒
element = driver.find_element(By.XPATH, "//li[text()='密码登录']")  # 定位【密码登录】元素
element.click()  # 点击确认

3.2、输账密点击登录

第二步,输入账号密码,并点击“登录豆瓣”按钮:

代码:

    element = driver.find_element(By.XPATH, "//input[@id='username']")  # 定位元素
    element.send_keys("18230630095")  # 输入内容
    element = driver.find_element(By.XPATH, "//input[@id='password']")  # 定位元素
    element.send_keys("123456")  # 输入内容
    element = driver.find_element(By.XPATH, "//a[text()='登录豆瓣']")  # 定位元素
    element.click()  # 点击按钮

3.3、切换焦点并下载验证图片

将焦点切换至滑块验证区域,并下载加载好的滑块验证背景图片。
点击登录按钮后,就会出现滑块验证区域,这是一个新增的frame区域,此时我们需要将切换的焦点从主页面转换到这个frame区域上:

代码:

driver.implicitly_wait(5)  # 隐式等待5秒
driver.switch_to.frame("tcaptcha_iframe_dy")  # 切换到frame区域

然后我们需要获取整个需要对其的大图片,获取其路径并下载到本地,准备进行读取验证:

下载图片效果:

代码:

 element = driver.find_element(By.XPATH, "//div[@id='slideBg']")  # 定位元素
 s = element.get_attribute("style")  # 获取元素值
 p = 'background-image: url\\(\\"(.*?)\\"\\);'  # 正则表达式 \\:表示转义
 img1 = re.findall(p, s, re.S)[0]  # re.S表示点号匹配任意字符,包括换行符
 print("滑块验证图片下载路径:", img1)  # 打印结果
 cs.add_img1(img1)  # 下载图片

3.4、拖动滑块至缺口处

我们接下来要做的,是将小拼图图片,移动到缺口处:

我们需要获取小图片到缺口处的实际距离,一般用到两种方法。
第一种方法是模板匹配,通过openCV分析两个图片的相似度,获取两个相似度很高图片的坐标,从而计算两个图片的距离。
第二种方法是轮廓检测,通过openCV进行轮廓检测,即在大图片中找到缺口位置的坐标,然后计算小图片到缺口位置的距离。
这里因为我们无法单独获取小拼图的单独图片,所以不好使用模板匹配的方法,所以我们选择使用第二种轮廓检测的方法。

(1)得到缺口轮廓位置信息

首先我们计算一下缺口的坐标及面积大概有多大,使用PhotoShop打开下载的图片,单独将缺口按照正方形的尺寸抠出来,发现其长宽各是80像素:

所以这个封闭矩形的面积范围大概是在80*80=6400像素左右。周长是80*4=320像素。但是现实中这里是有缺口的,不是一个完整的图片,所以我们需要给它一定的误差范围,这里我们暂定目标区域面积为上下百分之四,周长为上下百分之四。

然后我们将计算距离:

# 实例化一个类对象
cs = CrackSlider()
# 准备方法需要的入参
# 1、找到滑动按钮位置
element = driver.find_element(By.XPATH, "//div[@class='tc-fg-item tc-slider-normal']")
# 2、图片位置(相对当前项目)
img = 'img/img1.jpg'
# 3、缺口像素长宽(长宽必须一致)
gap_wide = 80
# 4、web图片宽度
web_wide = 340
# 5、原图片宽度
raw_wide = 672
# 调用方法获取返回的移动距离
dis = cs.get_pos(element, img, gap_wide, web_wide, raw_wide)
# 打印一下移动距离
print("dis=", dis)

执行结果:

生成的目标区域画红框的计算图片:

好了,到此为止我们获取到了一个重要的数据,就是缺口的位置信息。

(2)匹配小滑块元素

得到小滑块元素,让其移动位置到上面计算的距离。

注意:由于大部分网站有检测真人操作的逻辑,所以我们这里要模拟真人进行移动操作,不能一下移动到目标点,需要一点一点的移动。

# 调用方法移动滑块致缺口位置
# driver 浏览器驱动对象
# element 元素位置对象
# dis 移动距离
cs.slowly(driver, element, dis)
# 整体等待5秒看结果
time.sleep(5)
# 关闭浏览器
driver.quit()

执行结果

4、其他

4.1、浏览器获取元素

(1)打开F12

(2)选择元素

(3)复制元素XPath

(4)检验元素XPath唯一性

Ctrl+F唤起搜索

输入复制的XPath

查看是否唯一

  • 11
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
滑块验证码是一种通过用户鼠标移动滑块来填补有缺口图片的验证码。它的原理是首先生成一张带有缺口的图片,然后在页面上展示给用户。用户需要通过鼠标移动滑块,将滑块拖动到正确的位置,以填补缺口。通过JavaScript获取用户滑动距离和坐标等信息,并将这些信息发送给后台进行校验。只要用户的滑动距离和轨迹行为符合要求,即可视为验证通过。 在使用selenium处理滑块验证码时,可以利用selenium的方法对元素进行截图来获取验证码的图片。首先,找到包含滑块的HTML元素,然后使用selenium分别对完整图片和有缺口的图片进行截图。以下是获取完整图片和有缺口图片的示例代码: 获取完整图片: ''' def get_full_image(driver): """鼠标移动到滑块,显示完整图案 :param driver: webdriver :return: 返回验证码背景图片Image对象 """ webdriver.ActionChains(driver).move_to_element(slider).perform() time.sleep(0.2) img = driver.find_element_by_xpath('//*[@id="captcha"]/div/div/div/div/a') if 'show' in img.get_attribute('class'): res = img.screenshot_as_png return Image.open(BytesIO(res)) else: raise ValueError('获取验证码背景图片失败') ''' 获取有缺口的图片: ''' def get_cut_image(driver): """点击滑动按钮获取有缺口图片 :param driver: webdriver :return: 返回验证码有缺口图片的Image对象 """ slider = driver.find_element_by_xpath('//*[@id="captcha"]/div/div/div') webdriver.ActionChains(driver).click_and_hold(slider).perform() time.sleep(0.1) img = driver.find_element_by_xpath('//*[@id="captcha"]/div/div/div/div/a') res = img.screenshot_as_png cut_img = Image.open(BytesIO(res)) return Image.open(BytesIO(res)) ''' 以上代码可以通过selenium的ActionChains类模拟鼠标的移动和点击操作,分别获取到完整图片和有缺口的图片。 通过这些方法可以帮助你在处理selenium中的滑块验证码时获取到所需的图片,从而进行后续的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值