一、极验验证码(geetest)的三种验证模式

以极验官网登录(https://auth.geetest.com/login/)为例:

 

 在点击 “点击按钮进行验证”按钮后,会出现三种情况

1.点击直接通过

在一段时间的前几次登录时,点击按钮,会直接通过验证:

 

 

2.点击出现滑动验证码

登录几次后,再次登录时,就会出现滑动验证码:

 

 3.点击出现点触验证码:

登录过多时,就会出现点触验证码,这也是极验最难的一种验证码:

 

 

 二、分析

利用Python的selenium模块进行自动登录。

1.判断是否通过验证:

有一个类名为geetest_success_radar_tip的div标签,在加载后内容为空,验证成功后,内容变为“验证成功”,可以通过其内容来判断,是否验证成功。




下面是我截取的自己写的一段代码,主要是表达出含义,没有截取所有代码,理解就好:
    
self.success = self.browser.find_element_by_css_selector(\'.geetest_success_radar_tip\') # 获取显示结果的标签 def is_success(self): time.sleep(1) if self.success.text == "验证成功": return True else: return False

 


 


 2.点击直接通过

在点击“点击验证按钮”后,对是否验证成功进行一次判断,如果验证通过,则可以进行下一步动作。

3.滑动验证

滑动验证的标签是canvas,类名是geetest_canvas_slice,在点击“点击验证”后,如果是滑动验证,这个标签将会被加载,如果不是,则这个标签不会被加载。

所以可以通过查看是否存在这个标签,来判断验证是否是滑动验证:

    def is_slide(self):
        time.sleep(1)
        try:
            slie_img = self.browser.find_element_by_css_selector(\'canvas.geetest_canvas_slice\')
            if slie_img:
                return slie_img
        except NoSuchElementException:
            return False

 

如果是滑动验证,则可以通过比对有缺口图片和原图片,从而确定缺口的位置,然后模拟滑动滑块,从而达到验证的目的。具体操作,我在上一篇随笔中已经写过,请参考:
https://www.cnblogs.com/ohahastudy/p/11493971.html

4.点触验证

和滑动验证类似,点触验证可以通过判断是否存在类名为geetest_item_img的img标签来判断该验证为点触验证。

 

 

 

    def is_pick(self):
        try:
            pick_img = self.browser.find_element_by_css_selector(\'img.geetest_item_img\')
            return pick_img
        except NoSuchElementException:
            return False

 


保存该图片后,我们可以发现,该图片实际上是由两部分组成:

 


 图片中验证码的识别,我是通过超级鹰这个平台来识别的。按照超级鹰的文档,将图片发过去,并指明类型,在几秒之后会返回一个结果,内容含有需要识别模块的坐标,而其顺序也是按照上图中白色部分指定的顺序,可以说是非常贴心了。

获取坐标后,将坐标提取出来,然后通过模拟点击即可。

三、具体实现:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from PIL import Image
from six import BytesIO
import time
from selenium.webdriver import ActionChains
from selenium.common.exceptions import NoSuchElementException
import requests
import chaojiying  #超级鹰提供的模块,需要去官网下载


class Verifycode():

    def __init__(self):
        self.browser = webdriver.Chrome()

    def get_url(self, url, user, password):
        self.browser.get(url)
        self.browser.maximize_window()
        wait = WebDriverWait(self.browser, 10)
        wait.until(EC.presence_of_element_located((By.CLASS_NAME, \'geetest_radar_btn\')))
        user_input, pwd_input, *_ = self.browser.find_elements_by_css_selector(\'input.ivu-input\')
        print(user_input)
        btn = self.browser.find_element_by_css_selector(\'.geetest_radar_btn\')
        user_input.send_keys(user)
        pwd_input.send_keys(password)
        btn.click()
        time.sleep(1)
        self.success = self.browser.find_element_by_css_selector(\'.geetest_success_radar_tip\')  # 获取显示结果的标签

    def is_success(self):
        time.sleep(1)
        if self.success.text == "验证成功":
            return True
        else:
            return False

    def get_position(self, img_label):
        location = img_label.location
        size = img_label.size
        top, bottom, left, right = location[\'y\'], location[\'y\'] + size[\'height\'], location[\'x\'], location[\'x\'] + size[
            \'width\']
        return (left, top, right, bottom)

    def get_screenshot(self):
        screenshot = self.browser.get_screenshot_as_png()
        f = BytesIO()
        f.write(screenshot)
        return Image.open(f)

    def get_position_scale(self, screen_shot):
        height = self.browser.execute_script(\'return document.documentElement.clientHeight\')
        width = self.browser.execute_script(\'return document.documentElement.clientWidth\')
        x_scale = screen_shot.size[0] / (width + 10)
        y_scale = screen_shot.size[1] / (height)
        return (x_scale, y_scale)

    def get_slideimg_screenshot(self, screenshot, position, scale):
        x_scale, y_scale = scale
        position = [position[0] * x_scale, position[1] * y_scale, position[2] * x_scale, position[3] * y_scale]
        return screenshot.crop(position)

    def compare_pixel(self, img1, img2, x, y):
        pixel1 = img1.load()[x, y]
        pixel2 = img2.load()[x, y]
        threshold = 50
        if abs(pixel1[0] - pixel2[0]) <= threshold:
            if abs(pixel1[1] - pixel2[1]) <= threshold:
                if abs(pixel1[2] - pixel2[2]) <= threshold:
                    return True
        return False

    def compare(self, full_img, slice_img):
        left = 65
        for i in range(full_img.size[0]):
            for j in range(full_img.size[1]):
                if not self.compare_pixel(full_img, slice_img, i, j):
                    return i
        return left

    def get_track(self, distance):
        """
        根据偏移量获取移动轨迹
        :param distance: 偏移量
        :return: 移动轨迹
        """
        # 移动轨迹
        track = []
        # 当前位移
        current = 0
        # 减速阈值
        mid = distance * 4 / 5
        # 计算间隔
        t = 0.2
        # 初速度
        v = 0

        while current < distance:
            if current < mid:
                # 加速度为正 2
                a = 4
            else:
                # 加速度为负 3
                a = -3
            # 初速度 v0
            v0 = v
            # 当前速度 v = v0 + at
            v = v0 + a * t
            # 移动距离 x = v0t + 1/2 * a * t^2
            move = v0 * t + 1 / 2 * a * t * t
            # 当前位移
            current += move
            # 加入轨迹
            track.append(round(move))
        return track

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

    def is_slide(self):
        time.sleep(1)
        try:
            slie_img = self.browser.find_element_by_css_selector(\'canvas.geetest_canvas_slice\')
            if slie_img:
                return slie_img
        except NoSuchElementException:
            return False

    def slide_code(self):
        slice_img_label = self.browser.find_element_by_css_selector(\'div.geetest_slicebg\')  # 找到滑动图片标签
        self.browser.execute_script(
            "document.getElementsByClassName(\'geetest_canvas_slice\')[0].style[\'display\'] = \'none\'")  # 将小块隐藏
        full_img_label = self.browser.find_element_by_css_selector(\'canvas.geetest_canvas_fullbg\')  # 原始图片的标签
        position = self.get_position(slice_img_label)  # 获取滑动验证图片的位置
        screenshot = self.get_screenshot()  # 截取整个浏览器图片
        position_scale = self.get_position_scale(screenshot)  # 获取截取图片宽高和浏览器宽高的比例
        slice_img = self.get_slideimg_screenshot(screenshot, position, position_scale)  # 截取有缺口的滑动验证图片

        self.browser.execute_script(
            "document.getElementsByClassName(\'geetest_canvas_fullbg\')[0].style[\'display\'] = \'block\'")  # 显示原图
        screenshot = self.get_screenshot()  # 获取整个浏览器图片
        full_img = self.get_slideimg_screenshot(screenshot, position, position_scale)  # 截取原图
        self.browser.execute_script(
            "document.getElementsByClassName(\'geetest_canvas_slice\')[0].style[\'display\'] = \'block\'")  # 将小块重新显示
        left = self.compare(full_img, slice_img)  # 将原图与有缺口图片进行比对,获得缺口的最左端的位置
        left = left / position_scale[0]  # 将该位置还原为浏览器中的位置

        slide_btn = self.browser.find_element_by_css_selector(\'.geetest_slider_button\')  # 获取滑动按钮
        track = self.get_track(left)  # 获取滑动的轨迹
        self.move_to_gap(slide_btn, track)  # 进行滑动
        time.sleep(2)

    def is_pick(self):
        try:
            pick_img = self.browser.find_element_by_css_selector(\'img.geetest_item_img\')
            return pick_img
        except NoSuchElementException:
            return False

    def pick_code(self):
        time.sleep(1)
        pick_img_label = self.browser.find_element_by_css_selector(\'img.geetest_item_img\') #获取点触图片标签
        src = pick_img_label.get_attribute(\'src\')  #获取点触图片链接
        img_content = requests.get(src).content  #获取图片二进制内容
        f = BytesIO()
        f.write(img_content)
        img0 = Image.open(f)  #将图片以文件的形式打开,主要是为了获取图片的大小
        scale = [pick_img_label.size[\'width\'] / img0.size[0], pick_img_label.size[\'height\'] / img0.size[1]] #获取图片与浏览器该标签大小的比例
        cjy = chaojiying.Chaojiying_Client(\'*******\', \'******\', \'901489\') #登录超级鹰
        result = cjy.PostPic(img_content, \'9005\') #发送图片并获取结果
        if result[\'err_no\'] == 0:  #对结果进行分析
            position = result[\'pic_str\'].split(\'|\')  # position = [\'110,234\',\'145,247\',\'25,185\']
            position = [[int(j) for j in i.split(\',\')] for i in position]  # position = [[110,234],[145,247],[25,185]]
            for items in position:  #模拟点击
                ActionChains(self.browser).move_to_element_with_offset(pick_img_label, items[0] * scale[0],
                                                                       items[1] * scale[1]).click().perform()
                time.sleep(1)
            certern_btn = self.browser.find_element_by_css_selector(\'div.geetest_commit_tip\')
            certern_btn.click()
        return cjy,result


if __name__ == \'__main__\':

    verifycode = Verifycode()
    verifycode.get_url(\'https://gtaccount.geetest.com/\', \'11\', \'11\')
    if verifycode.is_success():
        print(\'success\')
    elif verifycode.is_slide():
        verifycode.slide_code()
        if verifycode.is_success():
            print(\'slide success\')
        else:
            print(\'slide failure\')
    elif verifycode.is_pick():
        cjy,result = verifycode.pick_code()
        if verifycode.is_success():
            print(\'pick click success\')
        else:
            print(\'pick click failure\')
            if result[\'err_no\'] == 0:
                r = cjy.ReportError(result[\'pic_id\'])
                print(r)

 




 

版权声明:本文为ohahastudy原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/ohahastudy/p/11518256.html