python爬虫之验证码篇3-滑动验证码识别技术

Python爬虫之验证码篇3-滑动验证码识别技术

本篇文章将带领大家学习如何使用Python进行滑动验证码识别技术,让我们能够愉快地完成爬虫任务,无需被恼人的滑动验证码阻挡。

前置技能

在学习本篇文章之前,您需要学会以下技能:

  • Python基础知识
  • Python爬虫入门基础
  • 了解验证码的基本原理

滑动验证码介绍

滑动验证码通常由一张包含有缺口的图片以及一个滑块组成,用户需要拖动滑块,使其到达缺口位置,才能验证身份。滑动验证码用于防止机器自动注册和登录,增强网站的注册和登录安全性。

滑动验证码攻略

1. 识别缺口位置

滑动验证码的关键在于识别缺口的位置,这个缺口的位置是不能预测的,需要通过一定的方式来确定。

我们可以使用selenium来模拟用户操作,拖动滑块,记录滑动前后的页面截图,然后使用图像识别技术找到滑块的移动距离,进而得出缺口的位置。

以下是示例代码:

from selenium import webdriver
from selenium.webdriver import ActionChains
import time
from PIL import Image
import math

def get_snap(driver):
    '''
    获取网页截图
    '''
    driver.save_screenshot('snap.png')
    snap_obj = Image.open('snap.png')
    return snap_obj

def get_image(driver, element):
    '''
    获取指定元素的截图
    '''
    location = element.location
    size = element.size
    left = location['x']
    top = location['y']
    right = left + size['width']
    bottom = top + size['height']

    # 截取指定位置的窗口
    snap_obj = get_snap(driver)
    image_obj = snap_obj.crop((left, top, right, bottom))
    return image_obj

def get_distance(image1, image2):
    '''
    获取两张图片的距离
    '''
    threshold = 100
    rgb1 = image1.convert('RGB')
    rgb2 = image2.convert('RGB')
    diffs = 0
    for i in range(0, rgb1.size[0]):
        for j in range(0, rgb1.size[1]):
            r, g, b = rgb1.getpixel((i, j))
            r2, g2, b2 = rgb2.getpixel((i, j))
            diff = abs(r - r2) + abs(g - g2) + abs(b - b2)
            if diff > threshold:
                diffs += diff

    return diffs

def get_track(distance):
    '''
    根据距离获取轨迹滑动的路线
    '''
    track = []
    current = 0
    mid = distance * 4 / 5
    t = 0.2
    v = 0

    while current < distance:
        if current < mid:
            a = 2
        else:
            a = -3
        v0 = v
        v = v0 + a * t
        move = v0 * t + 0.5 * a * t * t
        current += int(move)
        track.append(current)

    # 计算轨迹的减速部分
    extra = int(distance * 1.05) - current
    for i in range(extra):
        current += 1
        track.append(current)

    return track

def get_slider(driver):
    '''
    获取滑块对象
    '''
    slider = driver.find_element_by_xpath('//div[@class="login-pwd-code-content"]/div[2]')
    return slider

# 实例化WebDriver
driver = webdriver.Chrome()

# 打开登录页面
driver.get('https://www.zhihu.com/signin')

# 输入账号密码
driver.find_element_by_name('username').send_keys('test')
driver.find_element_by_name('password').send_keys('test123')

# 识别滑块位置
slider = get_slider(driver)
slider_img = get_image(driver, slider)
slider.click()

# 模拟滑块拖动
action = ActionChains(driver)
action.click_and_hold(slider).perform()

# 通过不断试验推算拖动位移
distance = 0
while distance == 0:
    action.move_by_offset(10, 0).perform()
    current_img = get_image(driver, slider)
    distance = get_distance(slider_img, current_img)
print('缺口位置距离', distance)        

track = get_track(distance)
for x in track:
    action.move_by_offset(x, 0).perform()

# 释放滑块,完成登录
action.release().perform()

2. 使用机器学习模型识别滑块验证码

除了使用图像识别技术识别滑块验证码,我们还可以使用机器学习模型进行识别。我们可以将滑块验证码的每一个位置看成一个像素点,并标记其是否为缺口(1为缺口,0为非缺口),然后训练机器学习模型进行识别。

以下是示例代码:

import cv2
import numpy as np
from sklearn.svm import SVC

def load_dataset():
    '''
    加载数据集
    '''
    # 加载正样本数据
    positive_images = []
    for i in range(100):
        image = cv2.imread('positive/{}.jpg'.format(i), 0)
        image = np.reshape(image, (20 * 20,))
        positive_images.append(image)

    # 加载负样本数据
    negative_images = []
    for i in range(200):
        image = cv2.imread('negative/{}.jpg'.format(i), 0)
        image = np.reshape(image, (20 * 20,))
        negative_images.append(image)

    # 将正负样本合并,打标签
    X = np.concatenate([positive_images, negative_images], axis=0)
    y = np.concatenate([np.ones(len(positive_images)), np.zeros(len(negative_images))])

    return X, y


def train_model():
    '''
    训练机器学习模型
    '''
    # 加载数据集
    X, y = load_dataset()

    # 训练模型
    model = SVC(kernel='linear', probability=True)
    model.fit(X, y)

    return model


def get_position(image, model):
    '''
    获取滑块位置
    '''
    row, col = image.shape
    stride = 5
    patches = []
    for i in range(0, row - stride, stride):
        for j in range(0, col - stride, stride):
            patch = image[i:i+stride, j:j+stride]
            patches.append(np.reshape(patch, (stride * stride, )))

    # 预测
    results = model.predict_proba(patches)[:, 1]
    results = np.reshape(results, (row // stride - 1, col // stride -1))
    max_prob = 0
    position = 0
    row, col = results.shape
    for i in range(row):
        for j in range(col):
            if i + 2 < row and j + 2 < col:
                sub_result = results[i:i+3, j:j+3]
                prob = np.mean(sub_result)
                if prob > max_prob:
                    max_prob = prob
                    position = (i + 1) * stride

    return position

# 加载机器学习模型
model = train_model()

# 加载验证码图片
image = cv2.imread('captcha.jpg', 0)

# 识别滑块位置
position = get_position(image, model)
print('缺口位置', position)

总结

通过学习本篇文章,我们了解了滑动验证码识别技术的原理和方法,并学会了使用Python进行滑动验证码的识别。无论是使用图像识别技术还是机器学习模型,都能够让我们愉快地完成爬虫任务,欢迎大家在实际应用中尝试。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:python爬虫之验证码篇3-滑动验证码识别技术 - Python技术站

(0)
上一篇 2023年6月11日
下一篇 2023年6月11日

相关文章

  • js 递归和定时器的实例解析

    JS 递归和定时器的实例解析 什么是递归? 递归是一种算法或函数设计技术,它是通过函数体内调用函数本身来完成的。通常情况下,递归函数是以递归式的表达式来定义的。简单来说,递归可以看作是把大的问题不断化解成相同的小问题,最终解决相同的小问题就能解决大的问题。 递归的示例 function sum(n) { if (n <= 1) return 1; re…

    JavaScript 2023年6月11日
    00
  • 实例讲解使用原生JavaScript处理AJAX请求的方法

    处理AJAX请求是现代Web开发中非常重要的一部分,可以轻松地从服务器加载数据并进行无需刷新页面的动态更新。原生JavaScript提供了一些内置的方法,可用于处理AJAX请求,并通过JavaScript代码与其他服务端技术交互。 以下是使用原生JavaScript处理AJAX请求的方法的完整攻略: 步骤一:创建XMLHttpRequest对象 XMLHtt…

    JavaScript 2023年6月11日
    00
  • 详解tween.js的使用教程

    详解tween.js的使用教程 什么是tween.js? tween.js是一款简单易用的JavaScript补间动画库,它可以让Web开发者很方便地创建和控制复杂的动画效果。它的特点是功能全面、易于使用,支持各种类型的动画插值器和缓动函数,以及灵活的回调函数和参数调整。此外,它还支持并行和序列动画,实现动画效果的细粒度控制。 如何使用tween.js? 1…

    JavaScript 2023年6月11日
    00
  • JavaScript引用类型Array实例分析

    JavaScript中,数组(Array)是一种引用类型(Reference Type),由一组有序的、可重复的元素组成,可以存在基本数据类型或其他引用类型的元素。以下是关于“JavaScript引用类型Array实例分析”的完整攻略。 一、创建数组 创建数组的方式有多种,以下是常见的几种方式: 1. 使用数组字面量(Array Literal) 数组字面量…

    JavaScript 2023年5月27日
    00
  • javascript 出生日期和身份证判断大全

    Javascript 出生日期和身份证判断大全 简介 本文主要讲解了如何使用Javascript判断身份证号和出生日期是否符合标准。 身份证号判断 校验规则 中国大陆的身份证号码是由18位数字组成的。最后一位为校验位,前17位为身份证号码的主体部分。其中,第1-2位为行政区划代码,第3-6位为出生年份(用4位数字表示),第7-10位为出生月份和日期(用2位数…

    JavaScript 2023年5月27日
    00
  • js使用split函数按照多个字符对字符串进行分割的方法

    使用split函数按照多个字符对字符串进行分割的方法,主要需要借助split()函数和正则表达式。下面将结合两个具体示例来详细讲解该方法的操作步骤。 示例一:使用split函数按照多个字符进行分割 假设有以下一个字符串: const str = ‘apple|pear?banana#orange’; 现在需要按照‘|’、‘?’和‘#’这三个字符对字符串进行分…

    JavaScript 2023年5月28日
    00
  • js正则表达式中test,exec,match方法的区别说明

    JS正则表达式是一种用于匹配字符串模式的工具,包括test、exec和match等方法可以用于匹配模式并返回匹配结果。这三种方法的用途和返回结果略有不同。我们来详细讲解一下这三种方法的区别说明。 1. test方法 test() 是正则表达式对象的一个方法,用于检测一个字符串是否匹配某个正则表达式。其返回值是一个布尔值,如果匹配成功返回 true,否则返回 …

    JavaScript 2023年6月10日
    00
  • js split 的用法和定义 js split分割字符串成数组的实例代码

    下面是关于JS的split函数的详细讲解: 定义 split是JavaScript中的字符串方法,可以将一个字符串分割成一个字符串数组。分割的标准可以是一个固定字符串,也可以是一个正则表达式。返回的字符串数组包含原始字符串中分割出的子字符串。 用法 split方法的语法格式如下: str.split(separator,limit) 参数说明: separa…

    JavaScript 2023年5月28日
    00
合作推广
合作推广
分享本页
返回顶部