破解滑动验证码(极验)

from selenium.webdriver import ActionChains
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium import webdriver
from io import BytesIO
from PIL import Image
import random
import time

class CrackGesstest(object):
    def __init__(self):
        self.url = 'https://www.geetest.com/type/'
        self.driver = webdriver.Chrome()
        self.wait = WebDriverWait(self.driver, 10)

    def __del__(self):
        self.driver.close()

    def openPage(self):
        """
        打开页面,显示出滑动验证码
        :return:
        """
        # 打开页面
        self.driver.get(self.url)
        # 选择滑动行为验证
        slide_button = self.wait.until(
            EC.element_to_be_clickable((By.XPATH, '//div[@class="products-content"]//li[2]')))
        slide_button.click()
        # 点击验证按钮
        verifi_button = self.wait.until(
            EC.element_to_be_clickable((By.XPATH, '//div[@class="geetest_radar_tip"]')))
        verifi_button.click()

    def getImage(self, img_name):
        """
        获得验证码图片
        :param img_name: 图片名称.png
        :return: image
        """
        # 获得验证码图片
        canvas = self.wait.until(
            EC.presence_of_element_located((By.XPATH, '//canvas[@class="geetest_canvas_slice geetest_absolute"]')))
        # 验证码位置
        position = self.imagePosition(canvas)
        # 屏幕截图
        screenshot = self.driver.get_screenshot_as_png()
        screenshot = Image.open(BytesIO(screenshot))
        # 从屏幕截屏中截取验证码图片
        image = screenshot.crop(position)
        image.save(img_name)
        print('图片保存完毕')
        return image

    def imagePosition(self, image_tag):
        """
        获得图片的位置信息
        :param image_tag:图片节点
        :return: 位置元组(left, top, right, bottom)
        """
        left = image_tag.location['x']
        # 根据实际情况改变数据大小(否则截图位置可能与实际验证码所在位置不一样,具体为什么还不懂)
        top = image_tag.location['y'] / 2
        right = left + image_tag.size['width']
        bottom = top + image_tag.size['height']
        return (left, top, right, bottom)

    def getDistante(self, img1, img2):
        """
        获得图片不同之处,距离图片左边的距离
        :param img1:残缺图片
        :param img2:完整图片
        :return: 距离
        """
        # 大概比滑块长度大一点
        distance = 60
        for i in range(distance, img1.size[0]):
            for j in range(1, img1.size[1]):
                if not self.isPixelEqual(img1, img2, i, j):
                    distance = i
                    return distance

        return distance


    def isPixelEqual(self,img1, img2, i, j):
        """
        判断两个像素点是否相同
        :param img1:残缺图片
        :param img2:完整图片
        :param i: 像素横坐标
        :param j: 像素纵坐标
        :return: bool
        """
        # 若某种颜色相差大于60,则认为不同
        xxx = 65
        rgb1 = img1.load()[i, j]
        rgb2 = img2.load()[i, j]
        if abs(rgb1[0] - rgb2[0]) < xxx and abs(rgb1[1] - rgb2[1]) < xxx and abs(rgb1[2] - rgb2[2]) < xxx:
            return True
        return False

    def getTracks(self, distance):
        """
        根据滑动距离设计滑动行为,避免被机器识别
        :param distance:滑块应该滑动的距离
        :return:forward_tracks(前向滑动距离),back_tracks(后向滑动距离)
        """
        # 初始位置
        x = 0
        # 初始速度
        v = 0
        # 每次滑动时间t
        t = [0.2, 0.1]
        # 前向滑动行为
        forward_tracks = []
        # 后项滑动行为,根据实际可进行更改
        back_tracks = [-6, -3, 2, 2, -3, -2, -2]
        # 取前五分之三进行加速,后面减速
        mid = distance * 3 / 5
        while x < distance + 5:
            if x < mid:
                a = 2
            else:
                a = -3
            i = random.randint(0, 1)
            # 每次滑动距离
            s = v * t[i] + 0.5 * a * t[i] * t[i]
            # 更新速度v
            v = v + a * t[i]
            # 更新当前位置
            x += s
            # 更新前向滑动行为
            forward_tracks.append(round(s))

        return forward_tracks, back_tracks

    def moveToGap(self, forward_tracks, back_tracks):
        """
        根据滑动行为,移动滑块到残缺地方
        :param forward_tracks: 前向滑动行为
        :param back_tracks: 后向滑动行为
        :return:
        """
        # 模拟鼠标点击住滑块
        button = self.wait.until(EC.presence_of_element_located((By.XPATH, '//div[@class="geetest_slider_button"]')))
        ActionChains(self.driver).click_and_hold(button).perform()
        # 拖动滑块
        for track in forward_tracks:
            ActionChains(self.driver).move_by_offset(xoffset=track, yoffset=0).perform()
        time.sleep(0.1)
        for back_track in back_tracks:
            ActionChains(self.driver).move_by_offset(xoffset=back_track, yoffset=0).perform()
        time.sleep(0.2)
        # 释放鼠标
        ActionChains(self.driver).release().perform()

    def crackStart(self):
        """
        进行破解验证码
        :return:
        """
        self.openPage()
        # 获得残缺验证码图片
        time.sleep(3)
        img_name = '1bg.png'
        bg_image = self.getImage(img_name)

        # 获得完成验证码图片
        self.driver.execute_script('document.querySelectorAll("canvas")[2].style=""')
        time.sleep(2)
        img_name = '1fullbg.png'
        fullbg_image = self.getImage(img_name)

        # 获取距离
        distance = self.getDistante(bg_image, fullbg_image)
        print('distance:', distance)

        # 获取滑动行为
        forward_tracks, back_tracks = self.getTracks(distance)
        print(forward_tracks)
        print(back_tracks)

        # 移动滑块
        self.moveToGap(forward_tracks, back_tracks)

        time.sleep(10)


def main():
    crack = CrackGesstest()
    crack.crackStart()
    print('work done!')


if __name__ == '__main__':
    main()

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_29666899/article/details/83929983