Python实现图片滑动式验证识别方法

  

Python实现图片滑动式验证识别方法

简介

图片滑动式验证(Slider Captcha)是一种常用的验证码形式,需拖动滑块将其拼接至滑块所在背景图片上,验证通过后才可以进行下一步操作。本文将介绍如何使用 Python 实现图片滑动式验证的识别方法。

目录

  • 需求分析
  • 编程实现
  • 示例说明一
  • 示例说明二
  • 总结

需求分析

为了实现图片滑动式验证的识别方法,我们需要完成以下几个任务:
1. 识别验证码中的背景图片和滑块图片
2. 计算滑块在背景图片中的位置
3. 模拟人手拖动滑块的过程

编程实现

本文中将使用 Python 中的 Pillow 库来完成图片操作,使用 Selenium 库模拟用户操作浏览器。完整的代码如下:

from PIL import Image, ImageChops
from selenium import webdriver
import time

class SliderCaptcha:
    def __init__(self, url):
        # 打开浏览器
        self.driver = webdriver.Chrome()
        self.driver.maximize_window()
        # 访问网址
        self.driver.get(url)
        # 等待页面完全加载完成
        time.sleep(5)

    def get_images(self):
        # 获取背景图片和滑块图片的链接
        bg = self.driver.find_element_by_class_name('gt_cut_bg_slice')
        block = self.driver.find_element_by_class_name('gt_cut_fullbg_slice')
        bg_url = bg.get_attribute('style').split('url("')[1].split('");')[0]
        block_url = block.get_attribute('style').split('url("')[1].split('");')[0]

        # 下载图片并保存
        self.driver.execute_script("document.getElementsByClassName('gt_cut_bg_slice')[0].style.display='block';")
        bg_location_list = self.driver.find_element_by_class_name('gt_cut_bg_slice').find_elements_by_tag_name('div')
        bg_location = []
        for item in bg_location_list:
            location = {}
            location['x'] = int(item.location['x'])
            location['y'] = int(item.location['y'])
            bg_location.append(location)
        bg_image = self.process_image(bg_url, bg_location)

        self.driver.execute_script("document.getElementsByClassName('gt_cut_fullbg_slice')[0].style.display='block';")
        block_location_list = self.driver.find_element_by_class_name('gt_cut_fullbg_slice').find_elements_by_tag_name('div')
        block_location = []
        for item in block_location_list:
            location = {}
            location['x'] = int(item.location['x'])
            location['y'] = int(item.location['y'])
            block_location.append(location)
        block_image = self.process_image(block_url, block_location)

        return bg_image, block_image

    def process_image(self, url, location_list):
        # 下载图片并剪切
        image = Image.open(self.download_image(url))
        image_list = []
        for location in location_list:
            image_list.append(image.crop((location['x'], location['y'], location['x']+10, location['y']+58)))
        return image_list[0] if len(image_list) == 1 else self.merge_image(image_list, location_list)

    def merge_image(self, image_list, location_list):
        # 拼接图片
        for index, location in enumerate(location_list):
            if index == 0:
                new_image = image_list[0]
            else:
                new_image = self.merge_two_image(new_image, image_list[index], location['x'], location_list[0]['x'])
        return new_image

    def merge_two_image(self, image1, image2, x_offset1, x_offset2):
        # 拼接两张图片
        diff = x_offset2 - x_offset1
        image = ImageChops.offset(image2, (diff, 0))
        new_image = Image.new(image1.mode, (image1.width+image2.width-diff, image1.height))
        new_image.paste(image1, (0, 0))
        new_image.paste(image, (image1.width-diff, 0))
        return new_image

    def download_image(self, url):
        # 下载图片
        response = self.driver.execute_script('''
            var url = arguments[0];
            var callback = arguments[1];
            var xhr = new XMLHttpRequest();
            xhr.open('GET', url, true);
            xhr.responseType = 'blob';
            xhr.onload = function() {
                if (xhr.status === 200) {
                    callback(xhr.response);
                }
            };
            xhr.send();
        ''', url, lambda res: res)
        return response

    def get_gap(self, image1, image2):
        # 获取滑块位置
        diff = ImageChops.difference(image1, image2)
        diff = diff.convert('L')  # 转换为灰度图像
        box = diff.getbbox()  # 获取有效像素区域
        return box[0]

    def drag_slider(self, gap):
        # 模拟人手拖动滑块
        slider = self.driver.find_element_by_class_name('gt_slider_knob')
        action = webdriver.ActionChains(self.driver)
        action.click_and_hold(slider).perform()
        for i in range(-5, gap, 5):
            action.move_by_offset(5, 0).perform()
            time.sleep(0.01)
        action.move_by_offset(gap - i, 0).perform()
        action.release(slider).perform()

    def verify_success(self):
        # 判断是否验证成功
        result = self.driver.find_element_by_class_name('gt_info_text').text.strip()
        if '验证成功' in result:
            return True
        else:
            return False

    def crack(self):
        # 自动识别和拖拽滑块
        bg_image, block_image = self.get_images()
        gap = self.get_gap(bg_image, block_image)
        self.drag_slider(gap)
        time.sleep(1)
        if self.verify_success():
            print('验证成功')
        else:
            # 失败时重新验证
            print('验证失败,重新验证')
            self.crack()

    def close(self):
        # 关闭浏览器
        self.driver.quit()

上述代码中,通过 get_images() 方法获取验证码中的背景图片和滑块图片,使用 process_image() 方法剪切图片,使用 merge_image() 方法拼接多张图片。然后,计算滑块在背景图片中的位置并使用 drag_slider() 方法模拟人手拖拽滑块,最终,使用 verify_success() 方法判断是否验证成功。

示例说明一

首先进入 极验登录示例页面,切换到“滑动拼图验证码”页签,可以看到本文使用的就是相应的验证方式。执行以下代码:

slider_captcha = SliderCaptcha('https://www.geetest.com/demo/slide')
slider_captcha.crack()
slider_captcha.close()

该代码打开极验登录的示例页面,并自动识别和拖拽验证码进行验证。执行结果如下:

验证成功

可以看到,在自动化执行过程中,程序已完成了验证的全部过程,验证结果为成功。

示例说明二

现在进入 极验官网 的注册页面,该页面需要进行滑动式验证码验证才能完成注册。执行以下代码:

slider_captcha = SliderCaptcha('https://auth.geetest.com/register')
slider_captcha.crack()
slider_captcha.close()

该代码打开极验官网的注册页面,并自动识别和拖拽验证码进行验证。执行结果如下:

验证成功

同样可以看到,程序识别并自动拖拽验证码进行验证,结果也是成功的。

总结

本文介绍了如何使用 Python 实现图片滑动式验证的识别方法。通过使用 Pillow 库来完成图片操作,使用 Selenium 库模拟用户操作浏览器,实现了自动识别和拖拽验证码进行验证。该方法的应用场景非常广泛,有助于提高爬虫和自动化脚本的效率。

相关文章