Selenium+opencv识别有缺口的滑动验证码

完整代码我放文末

这里的有缺口图片我指的是这种类型的哈(验证码网站:https://pintia.cn/auth/login)

第一步:先创建一个driver对象访问该网站,并配置一些信息防止网站识别出是驱动的

 def __init__(self):
        """构造方法设置配置一些启动项"""
        super(CrackSlider, self).__init__()
        self.opts = webdriver.ChromeOptions()
        self.opts.add_experimental_option('excludeSwitches', ['enable-logging'])
        self.opts.add_experimental_option('useAutomationExtension', False)  # 禁用Chrome的自动化拓展程序
        self.opts.add_experimental_option('excludeSwitches', ['enable-automation'])  # 确保浏览器不会因为启用自动化模式而出现不必要的错误或异常。
        self.opts.add_argument("--disable-blink-features=AutomationControlled")  # 禁用由自动化测试或脚本控制的 Blink 功能。
        chrome_path = r"chromedriver.exe"  # google驱动路径
        self.driver = webdriver.Chrome(chrome_path, options=self.opts)
        self.url = 'https://pintia.cn/auth/login'  # 滑块验证码的地址
        self.wait = WebDriverWait(self.driver, 10)

第二步:就点点到有验证码的页面呗,然后保存两张图片

def get_pic(self):
        self.driver.get(self.url)  # 访问地址
        time.sleep(3)
        self.driver.find_element(by=By.XPATH, value='//*[@id="username"]').send_keys("2313859086@qq.com")
        self.driver.find_element(by=By.XPATH, value='//*[@id="password"]').send_keys("bo18212410475")
        self.driver.find_element(by=By.XPATH,
                                 value='//*[@id="sparkling-daydream"]/div[2]/div/div[2]/div[2]/button/div/div').click()
        time.sleep(3)  # 可以设置久一些,方便页面充分加载出来
        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('PTA_A.jpg')  # 保存图片

        template_img.save('PTA_B.png')

也就是图片一(含缺口图片)

还有图片二(滑块的图片)

第三步:就到了我们利用深度学习的opencv库读取我们两个图片然后识别出他们之间的距离

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:
        """如果是三通道就用add_alpha_channel转为4通道"""
        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)  # 计算输入图像 img 与模板图像 small_img 的相似度

    value = cv2.minMaxLoc(res_TM_CCOEFF_NORMED)  # 计算输入图像与模板图像的相似度,并找到相似度最高的区域

    value = value[3][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

第四步:不要学网上那种什么魔幻滑动公式s = v * t + 0.5 * a * (t ** 2),直接在滑动的时候添加抖动就可以了(也就是yoffset设置小数点)

   def crack_slider(self, distance):
        """得到了需要向右滑动的距离distance值"""
        slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'yidun_slider__icon')))  # 等待滑块出来
        ActionChains(self.driver).click_and_hold(slider).perform()  # 按住滑块
        # 魔幻运动
        ActionChains(self.driver).move_by_offset(xoffset=distance - 5, yoffset=0.81).perform()
        ActionChains(self.driver).move_by_offset(xoffset=3, yoffset=0.77).perform()
        ActionChains(self.driver).move_by_offset(xoffset=2, yoffset=-1.3).perform()
        ActionChains(self.driver).pause(1).perform()
        # 松开鼠标
        ActionChains(self.driver).release().perform()  # 松开鼠标
        time.sleep(0.5)
        try:
            wait = WebDriverWait(self.driver, 5)  # 设置最长等待时间为20秒
            # 大概意思就是设置20秒的等待时间,然后如果滑动准确,就会找到其他地方,然后跳转
            slider = wait.until(EC.presence_of_element_located((By.XPATH,
                                                                '//*[@id="sparkling-daydream"]/div[1]/div/div[1]/a[2]/div/divxxx')))
            slider.click()
            print('yes')
        except TimeoutException:
            cs = CrackSlider()
            cs.get_pic()
            # 2. 对比图片,计算距离
            img_jpg_path = 'a.jpg'  # 读者可自行修改文件路径(我保存的是在本地)
            img_png_path = 'b.png'
            distance = match(img_jpg_path, img_png_path)  # 可以得到需要滑动的值
            distance = distance + 9  # 距离的进一步特殊处理
            # 3. 移动
            cs.crack_slider(distance)
        finally:
            self.driver.quit()

另外添加了一个滑动不过就继续重新滑处理,不过我一般在滑动所有这种类似网站的验证码都是一遍过

第五步:差点忘记提醒一个地方了,最后识别出距离了,然后查看照片的分辨率和页面上的分辨率是否一致,

如果不一致就转换一下,如果某些网站精度要较高,则可以加减一些数字,微调

distance = distance / 图片实际的x * 页面上的x

如果图片实际为30*15
页面上为48*36
则distance = distance/30*48

完整代码如下

import requests
import time
from io import BytesIO
import cv2
import numpy as np
from PIL import Image
from selenium import webdriver  # selenium版本3.141.0配合urllib3版本1.26.0(其他包默认最新)
from selenium.common.exceptions import TimeoutException
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.opts.add_experimental_option('useAutomationExtension', False)  # 禁用Chrome的自动化拓展程序
        self.opts.add_experimental_option('excludeSwitches', ['enable-automation'])  # 确保浏览器不会因为启用自动化模式而出现不必要的错误或异常。
        self.opts.add_argument("--disable-blink-features=AutomationControlled")  # 禁用由自动化测试或脚本控制的 Blink 功能。
        chrome_path = r"./Selenium/chromedriver.exe"  # google驱动路径
        self.driver = webdriver.Chrome(chrome_path, options=self.opts)
        self.url = 'https://pintia.cn/auth/login'  # 滑块验证码的地址
        self.wait = WebDriverWait(self.driver, 10)

    def get_pic(self):
        self.driver.get(self.url)  # 访问地址
        time.sleep(3)
        self.driver.find_element(by=By.XPATH, value='//*[@id="username"]').send_keys("2313859086@qq.com")
        self.driver.find_element(by=By.XPATH, value='//*[@id="password"]').send_keys("bo18212410475")
        self.driver.find_element(by=By.XPATH,
                                 value='//*[@id="sparkling-daydream"]/div[2]/div/div[2]/div[2]/button/div/div').click()
        time.sleep(3)  # 可以设置久一些,方便页面充分加载出来
        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('PTA_A.jpg')  # 保存图片

        template_img.save('PTA_B.png')

    def crack_slider(self, distance):
        """得到了需要向右滑动的距离distance值"""
        slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'yidun_slider__icon')))  # 等待滑块出来
        ActionChains(self.driver).click_and_hold(slider).perform()  # 按住滑块
        # 魔幻运动
        ActionChains(self.driver).move_by_offset(xoffset=distance - 5, yoffset=0.81).perform()
        ActionChains(self.driver).move_by_offset(xoffset=3, yoffset=0.77).perform()
        ActionChains(self.driver).move_by_offset(xoffset=2, yoffset=-1.3).perform()
        ActionChains(self.driver).pause(1).perform()
        # 松开鼠标
        ActionChains(self.driver).release().perform()  # 松开鼠标
        time.sleep(0.5)
        try:
            wait = WebDriverWait(self.driver, 5)  # 设置最长等待时间为20秒
            # 大概意思就是设置20秒的等待时间,然后如果滑动准确,就会找到其他地方,然后跳转
            slider = wait.until(EC.presence_of_element_located((By.XPATH,
                                                                '//*[@id="sparkling-daydream"]/div[1]/div/div[1]/a[2]/div/divxxx')))
            slider.click()
            print('yes')
        except TimeoutException:
            cs = CrackSlider()
            cs.get_pic()
            # 2. 对比图片,计算距离
            img_jpg_path = 'PTA_A.jpg'  # 读者可自行修改文件路径(我保存的是在本地)
            img_png_path = 'PTA_B.png'
            distance = match(img_jpg_path, img_png_path)  # 可以得到需要滑动的值
            distance = distance + 9  # 距离的进一步特殊处理
            # 3. 移动
            cs.crack_slider(distance)
        finally:
            self.driver.quit()


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:
        """如果是三通道就用add_alpha_channel转为4通道"""
        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)  # 计算输入图像 img 与模板图像 small_img 的相似度
    value = cv2.minMaxLoc(res_TM_CCOEFF_NORMED)  # 计算输入图像与模板图像的相似度,并找到相似度最高的区域
    value = value[3][0]  # 获取到移动距离
    return value


if __name__ == '__main__':
    cs = CrackSlider()
    cs.get_pic()
    # 2. 对比图片,计算距离
    img_jpg_path = 'PTA_A.jpg'  # 读者可自行修改文件路径(我保存的是在本地)

    img_png_path = 'PTA_B.png'

    distance = match(img_jpg_path, img_png_path)  # 可以得到需要滑动的值

    distance = distance + 9  # 距离的进一步特殊处理
    # 3. 移动
    cs.crack_slider(distance)

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Python Selenium可以通过模拟鼠标滑动的方式来识别滑动验证码。具体实现方法可以参考以下步骤: 1. 使用Selenium打开网页并定位到包含滑动验证码的页面。 2. 利用Selenium的find_element_by_xpath()方法定位到验证码的滑块元素和背景图片元素。 3. 利用Selenium的ActionChains类模拟鼠标滑动操作,将滑块元素拖动到背景图片元素的位置。 4. 判断是否成功通过验证验证,如果验证成功则继续进行后续操作,否则重新进行验证识别。 需要注意的是,滑动验证码的实现方式可能因网站而异,因此具体实现方法需要根据实际情况进行调整。 ### 回答2: Python Selenium是一种自动化测试工具,可以用于控制浏览器执行自动化操作,比如滑动验证识别滑动验证码通常是用于网站的登陆、注册等操作,通过鼠标模拟人手在滑动拼图或滑动滑块,达到人机交互的效果。在自动化测试中,如果能够识别滑动验证码,就可以实现完全自动化,提高效率。下面将介绍如何使用Python Selenium进行滑动验证识别。 首先,需要安装Python3.x环境和Selenium库,可以通过pip install selenium命令进行安装。同时,还需要下载Chrome浏览器和对应的ChromeDriver,可以在官网下载,或者使用pip install chromedriver-binary命令安装。 1. 首先,需要定位滑块和背景图片。使用Selenium中的find_element_by_xpath方法或find_element_by_css_selector方法,根据网页源代码中的滑动拼图或滑动滑块的html标签和属性进行定位。同时,需要获取到背景图片的url。 2. 使用Python中的requests库获取背景图片,并将其保存到本地。根据所在位置的XPath表达式或CSS选择器,获取滑块或滑块背景的定位参数。 3. 使用Pillow库加载图片,并用crop方法获取到滑块的图片,并用convert方法将图片转换成灰度图片。 4. 判断图片的边缘信息,使用Sobel算子检测像素的边缘信息,通过循环或递归,找出图像中各个切割线的位置。 5. 根据切割线的位置计算出滑块需要滑动的距离,并使用Selenium中的ActionChains类,模拟鼠标移动和滑动操作,使其滑动到正确的位置。 以上就是Python Selenium滑动验证识别的主要方法和步骤。需要注意的是,滑块验证码一般采用了加密算法和图像处理技术,为防止自动化操作,可能经过多次变换和加密,同时还有可能加入噪声干扰。因此,需要根据实际情况,灵活运用Python的图像处理、机器学习和深度学习等技术,提高验证码的识别率和稳定性。 ### 回答3: 近年来,网站安全性越来越高,许多网站为了避免机器人恶意攻击,采用了滑动验证码。与传统的验证码相比,滑动验证码安全性更高,更难被攻击者破解。但是,这也给爬虫程序带来了困难。Python Selenium是一款非常出色的自动化测试工具,可以用来模拟浏览器行为,也可以用于爬虫。那么,如何利用Python Selenium实现滑动验证识别呢? 在滑动验证识别中,可以采取以下一些方案。 第一种: 使用第三方平台 目前,市面上有很多第三方平台可以识别验证码,例如:云打码、Python Tesseract等,这些平台可以帮助我们完成验证码的识别过程。在使用这些平台时,需要先在该平台进行注册,获得API key后再通过Python Selenium调用API进行验证码的输入和识别。 第二种: 随机滑动并比对结果 另外一种解决方案是,随机化模拟用户滑动,并比对结果。这种方法需要在页面加载完成后,获取验证码图片,并使用Python的Pillow库进行处理。处理完成后,可以随机模拟用户滑动,然后比对滑块位置是否正确。当验证通过时,继续模拟其他操作即可。 第三种: 内容识别并自动滑动 第三种方案是,利用Python的图像识别库,如OpenCV、PIL等,在页面加载完成后,对验证码图片进行特征提取,然后通过算法自动计算出正确的滑块位置,并模拟用户滑动。 总的来说,三种方案各有优缺点,不同的方案适用于不同的验证码,具体选择哪种方案,需要综合考虑多方面的因素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值