python爬虫之selenium识别滑动验证码

最早在爬虫中遇到滑动验证码是在国家企业信用信息公示系统中,当时也是运用selenium来完成。现在该网站已经改为点触验证码了,故现在用bilibili登录页面作为一个示例。

一、识别思路

识别滑动验证码需要完成如下几步:

1)模拟点击验证按钮

2)得到完整的验证码图片

3)得到带缺口的验证码图片

4)比较图片的像素差异,识别缺口

5)模拟滑动动作

二、初始化

b站的登录地址为https://passport.bilibili.com/login,需要预先注册好的账号

class BilibiliLogin():
    def __init__(self):
        self.url = 'https://passport.bilibili.com/login'
        self.browser = webdriver.Chrome()
        self.wait = WebDriverWait(self.browser, 10)
        self.username = username
        self.password = password

三、模拟点击

实现思路中的第一步,点击按钮显示完整的滑动验证码图片,然后实现第二步得到完整图片

python爬虫之selenium识别滑动验证码_第1张图片

点击圈中按钮,会显示完整的图片

def get_button(self):
    """
    获取初始验证按钮
    :return:
    """
    button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'gt_ajax_tip')))
    return button

通过分析节点信息,得到图片位置并保存图片

def get_position(self):
    """
    获取验证码位置
    :return: 验证码位置元组
    """
    img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'gt_cut_fullbg')))
    time.sleep(2.5)
    location = img.location
    size = img.size
    top, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size[
            'width']
    return (top, bottom, left, right)

def get_image(self, image):
    """
    获取验证码图片
    :return: 图片对象
    """
    top, bottom, left, right = self.get_position()
    screenshot = self.get_screenshot()
    captcha = screenshot.crop((left, top, right, bottom))
    captcha.save(image)
    return captcha

python爬虫之selenium识别滑动验证码_第2张图片

单击一下滑动按钮,会出现缺口,再调用get_image()方法,得到带有缺口的图片。

四、识别缺口

def get_gap(self, image1, image2):
    """
    获取缺口偏移量
    :param image1: 不带缺口图片
    :param image2: 带缺口图片
    :return:
    """
    left = 60
    for i in range(left, image1.size[0]):
        for j in range(image1.size[1]):
            print(self.is_pixel_equal(image1, image2, i, j))
            if not self.is_pixel_equal(image1, image2, i, j):
                left = i
                return left
    return left

def is_pixel_equal(self, image1, image2, x, y):
    """
    判断两个像素是否相同
    :param image1: 图片1
    :param image2: 图片2
    :param x: 位置x
    :param y: 位置y
    :return: 像素是否相同
    """
    # 取两个图片的像素点
    pixel1 = image1.load()[x, y]
    pixel2 = image2.load()[x, y]
    threshold = 20
    if abs(pixel1[0] - pixel2[0]) < threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs(
            pixel1[2] - pixel2[2]) < threshold:
        return True
    else:
        return False

五、滑动滑块

在拖动滑块的时候,我借鉴了网上的一些经验,为模拟人的动作,拖动滑块应该是先加速后减速,所以构造了一个track函数,整个操作本身直接用selenium的动作链完成即可。

def move_to_gap(self, slider, track):
    """
    拖动滑块到缺口处
    :param slider: 滑块
    :param track: 轨迹
    :return:
    """
    ActionChains(self.browser).click_and_hold(slider).perform()
    for x in track:
        ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform()
    time.sleep(0.5)
    ActionChains(self.browser).release().perform()

六、实现效果

效果如下gif动图,完整代码以后上传到github。

你可能感兴趣的:(python,selenium)