沃梦达 / IT编程 / 前端开发 / 正文

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

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

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-滑动验证码识别技术