Selenium爬取滑动验证码

268 阅读2分钟
import base64
import json
import os
import random
import sys
import time

import requests
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait

sys.path.append(os.path.dirname(os.path.abspath(__file__)))





# 滑动验证码识别
class Code():
    '''
        滑动验证码识别
    '''

    def __int__(self, slider_ele=None, background_ele=None, count=1, save_image=False):
        '''
        参数:
        : params: slider_ele:滑块元素
        : params: background_ele:背景元素
        : params: count:尝试次数
        : params: save_image:是否保存图片  默认不保存
        '''
        self.count = count
        self.save_images = save_image
        self.slider_ele = slider_ele
        self.background_ele = background_ele

    def get_slide_locus(self, distance):
        '''
        计算滑块的滑动轨迹
        :param distance: 偏移量
        :return: 滑动轨迹
        '''
        # 总距离增加8
        distance += 7.9
        # 初始速度为0
        v = 0
        # 计算时间间隔
        m = 0.3
        # 移动轨迹
        tracks = []
        # 定义一个当前位置变量,初始值为0
        current = 0
        # 减速阈值
        mid = distance * 4 / 5
        while current <= distance:
            # 如果当前位置小于减速阈值,速度增加(加速度)
            if current < mid:
                a = 2
            else:
                a = -3
            # 初速度
            v0 = v
            # 当前速度
            s = v0 * m + 0.6 * a * (m ** 2)
            # 当前位置
            current += s
            # 将位移添加到列表中
            tracks.append(round(s))
            v = v0 + a * m  # 更新速度
        return tracks

    def slide_verification(self, driver, slide_element, distance):
        '''
        滑动验证
        :param driver: 浏览器驱动
        :param slide_element: 滑块元素
        :param distance: 滑动距离
        :return: 是否验证成功
        '''
        # 根据滑动距离生成滑动轨迹
        locus = self.get_slide_locus(distance)

        # 按下鼠标左键
        ActionChains(driver).click_and_hold(slide_element).perform()

        time.sleep(0.5)

        # 遍历轨迹进行滑动
        for loc in locus:
            time.sleep(0.01)
            # 源码的活动速度太慢,修改move_by_offset->move_by->create_pointer_move的DEFAULT_MOVE_DURATION 为50
            ActionChains(driver).move_by_offset(loc, random.randint(-5, 5)).perform()
            ActionChains(driver).context_click(slide_element)

        # 释放鼠标
        ActionChains(driver).release(on_element=slide_element).perform()

    def onload_save_img(self, url, filename='image.png'):
        try:
            response = requests.get(url)
        except Exception as e:
            print('图片下载失败')

        else:
            with open(filename, 'wb') as f:
                f.write(response.content)


class Login(object):

    def __init__(self, user, password, retry):
        # 创建一个参数对象,用来控制chrom以无界面模式打开
        browser_options = webdriver.ChromeOptions()
        # 这段代码用于禁用浏览器扩展功能
        browser_options.add_argument('--disable-extensions')
        # 这段代码用于启用 Chrome 浏览器的调试功能,并将调试器的地址设置为 127.0.0.1:9222
        browser_options.add_experimental_option('debuggerAddress', '127.0.0.1:9222')

        self.browser = webdriver.Chrome(browser_options)
        self.wait = WebDriverWait(self.browser, 20)
        self.url = 'https://txzbqy.miit.gov.cn/#/gateway/list'
        self.sli = Code()
        self.user = user
        self.password = password
        self.retry = retry

    def login(self):

        self.browser.get('https://www.dadan.vip/')

        time.sleep(2)

        # 请求网址
        self.browser.get(self.url)

        time.sleep(2)

        self.browser.find_element(By.XPATH, '//div[@class="invite"]/header/span').click()

        k = 1

        while k < self.retry:
            time.sleep(3)

            # 验证码背景
            bg_img = self.browser.find_element(By.XPATH, '//img[@class="slide-canvas"]').get_attribute('src')
            # 验证码滑块
            front_image = self.browser.find_element(By.XPATH, '//img[@class="slide-block"]').get_attribute('src')
            # ???
            slider_button_location = self.browser.find_element(By.XPATH, '//div[@class="slider-button-icon"]').location

            custom_url = "http://api.jfbym.com/api/YmServer/customApi"
            token = "yhq"
            headers = {'Content-Type': 'application/json'}

            # payload = {"image": bg_img, "token": token, "type": 22222, "extra": 'true'}
            payload = {"slide_image": front_image, "token": token, "type": 20111, "background_image": bg_img}
            resp = requests.post(custom_url, headers=headers, data=json.dumps(payload))
            # 缩放比例(实际滑动距离)
            distutils = resp.json()['data']['data']
            # 滑动对象
            element = self.browser.find_element(By.XPATH, '//div[@class="slider-button"]')
            # 滑动函数
            self.sli.slide_verification(self.browser, element, int(distutils))

            time.sleep(5)

    def get_cookies(self):
        # 登陆成功,保存cookie
        cookies = self.browser.get_cookies()
        self.cookies = ''

        for cookie in cookies:
            self.cookies += '{}={};'.format(cookie.get('name'), cookie.get('value'))

        return cookies

    def __del__(self):
        self.browser.close()
        print('页面关闭')


if __name__ == '__main__':
    l = Login('用户名', '密码', 6)
    l.login()