阳泉北站列车时刻表:What?废柴, 模拟上岸,代码控制滑动验证真的很难吗?Are you kidding???

admin 5个月前 (06-05) 科技 49 1

1.简介

  在前边的python接口自动化的时刻,我们由于博客园的登录机制的改变,没有用博客园的登录测试接口。那么博客园现在酿成了滑动验证登录,而且现在绝大多数的登录都酿成这种滑动验证和验证码的登录验证机制。我们真的没有其他设施解决这种验证机制的登录了吗?真的是一筹莫展了吗?谜底是:NO,今天宏哥教你若何用代码来模拟鼠标滑动,最终验证乐成后,最后乐成登录。那么怎么做了,思绪了???

2.我们首先明白滑动验证的原理

滑动验证难点
1.电脑若何自动点击滑动块
2.电脑若何检测 缺口位置(如图;)

3.解决这两个问题方式

  1. 若何自动点击滑动块,也就是图中的左下方圈起来的位置,我们可以使用selenium
  2. 怎么盘算缺口的位置,我们可以通过PIL库的image

4.博客园登录

  既然有了解决方式,我们看一下博客园的登录思绪:

(1)首先我们需要打开登录页面,并输入用户名和密码,点击登录按钮,弹出验证码图片;(这个对照简朴也容易实现)

(2)其次我们需要获取2张验证码图片,带缺口和不带缺口;

(3)最后我们需要获取缺口位置。遍历带缺口的图片和不带缺口的图片的每个像素,行使 is_pixel_equal() 方式判断两张图片统一位置的像素是否相同。对照两张图 RGB 的绝对值是否均小于界说的阈值 thresold。若是绝对值均在阈值之内,则代表像素点相同,继续遍历。否则代表不相同的像素点,就是缺口的位置。
  通过对比两张图片可以发现,两张图片有两处显著差别的地方:一个是待拼合的滑块,一个是缺口。滑块的位置会出现在左边位置,缺口会出现在与滑块统一水平线的位置,以是缺口一样平常会在滑块的右侧。若是要寻找缺口,直接从滑块右侧寻找即可。这里直接设置遍历的起始横坐标为60,也就是从滑块的右侧最先识别,这样识别出的效果就是缺口的位置。

下图就是用来说明若何对比图片:

 思绪我们清晰了,那我们就最先撸代码吧。

4.1代码实现:

4.2参考代码:

# coding=utf-8

# 1.先设置编码,utf-8可支持中英文,如上,一样平常放在第一行

# 2.注释:包罗纪录建立时间,建立人,项目名称。
'''
Created on 2019-5-13
@author: 北京-宏哥   QQ交流群:705269076
Project: What?废柴, 模拟上岸,代码控制滑动验证真的很难吗?Are you kidding???
'''

# 3.导入模块
import time
from io import BytesIO
from PIL import Image
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

USERNAME = '博客园的username'
PASSWORD = '博客园的password'
BORDER = 6

class CrackGeetest():
    def __init__(self):
        self.url = 'https://passport.cnblogs.com/user/signin'
        self.url = 'https://passport.cnblogs.com/user/signin'
        self.browser = webdriver.Chrome('E:\\untitled\\automation_framework_demo\\tools\chromedriver.exe')
        # self.browser.maximize_window()  # 将Chrome窗口放大
        self.wait = WebDriverWait(self.browser, 20)
        self.username = USERNAME
        self.password = PASSWORD

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

    def get_login_button(self):
        """
        获取登录按钮,调出极验验证码
        :return: 登录按钮工具
        """
        #button_login = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'button')))
        button_login = self.wait.until(EC.element_to_be_clickable((By.ID, 'submitBtn')))
        return button_login

    def get_geetest_button(self):
        """
        获取初始验证按钮,即点击按钮举行验证
        :return: 按钮工具
        """
        button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_slider_button')))
        return button

    def get_position(self, flag):
        """
        获取验证码位置
        :return: 验证码位置元组
        """
        img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_canvas_img')))
        fullbg = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, "geetest_canvas_fullbg")))
        time.sleep(2)

        if flag:
            self.browser.execute_script(
                "arguments[0].setAttribute(arguments[1], arguments[2])", fullbg, "style", "")
            print("获取不带缺口的图片乐成")
        else:
            self.browser.execute_script(
                "arguments[0].setAttribute(arguments[1], arguments[2])", fullbg, "style", "display: none")
            print("获取带缺口的图片乐成")

        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, size)

    def get_screenshot(self):
        """
        获取网页截图
        :return: 截图工具
        """
        screenshot = self.browser.get_screenshot_as_png()
        screenshot = Image.open(BytesIO(screenshot))
        return screenshot

    def get_slider(self):
        """
        获取滑块
        :return: 滑块工具
        """
        slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_slider_button')))
        return slider

    def get_geetest_image(self, flag, name='captcha.png'):
        """
        获取验证码图片
        :return: 图片工具
        """
        top, bottom, left, right, size= self.get_position(flag)
        print('验证码位置', top, bottom, left, right, size)
        screenshot = self.get_screenshot()
        # 凭据验证码图像位置获取验证码图像
        captcha = screenshot.crop((left, top, right,bottom))
        #captcha.save(name)
        return captcha

    def open(self):
        """
        打开网页输入用户名密码
        :return: None
        """
        self.browser.get(self.url)
        username = self.wait.until(EC.presence_of_element_located((By.ID, 'LoginName')))
        password = self.wait.until(EC.presence_of_element_located((By.ID, 'Password')))
        username.send_keys(self.username)
        password.send_keys(self.password)

    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]):
                if not self.is_pixel_equal(image1, image2, i, j):
                    # left = i
                    # return left
                    return i
        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]
        #print("piexl1", pixel1, "piexl2", pixel2)
        threshold = 60
        if abs(pixel1[0] - pixel2[0]) < threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs(
            pixel1[2] - pixel2[2]) < threshold:
            #print("True")
            return True
        else:
            #print("False")
            return False

    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 = 2
            else:
                # 加速率为负3
                a = -3
            # 初速率v0
            v0 = v
            # 当前速率v = v0 + a * t
            v = v0 + a * t
            # 移动距离 x = v0*t + 1/2 * a * t^2
            move = v0 * t + 0.5 * a * t * t
            # 当前位移
            current += move
            # 加入轨迹
            track.append(round(move))
        return track

    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()

    def login(self):
        """
        登录
        :return: None
        """
        # submit = self.wait.until(EC.element_to_be_clickable((By.ID, 'submitBtn')))
        # submit.click()
        # time.sleep(10)
        print('登录乐成')

    def crack(self):
        # 输入用户名和密码
        self.open()
        # 点击登录按钮,调出验证按钮
        login_button = self.get_login_button()
        login_button.click()

        # 获取验证码图片,不带缺口
        image1 = self.get_geetest_image(True, 'captcha1.png')
        # 点按呼出缺口图片,获取滑块
        slider = self.get_slider()
        # slider.click()    # 现在不需要点击滑块即可呼出缺口图片
        # 获取带缺口的验证码图片
        image2 = self.get_geetest_image(False, 'captcha2.png')

        # 获取缺口位置
        gap = self.get_gap(image1, image2)
        print('缺口位置', gap)

        # 减去缺口位移
        gap -= BORDER

        # 获取移动轨迹
        track = self.get_track(gap)
        print('滑动轨迹', track)

        # 拖动滑块
        self.move_to_gap(slider, track)

        try:
            success = self.wait.until(
                EC.text_to_be_present_in_element((By.CLASS_NAME, 'geetest_panel_success_title'), '通过验证'))
            print(success)
            #self.login()
        except Exception:
            self.crack()

        if success:
            print(success)
            self.login()


if __name__ == '__main__':
    crack = CrackGeetest()
    crack.crack()

4.3运行效果:

运行代码后,控制台打印如下图的效果

阳泉北站列车时刻表:What?废柴, 模拟上岸,代码控制滑动验证真的很难吗?Are you kidding??? 第1张

从运行效果,我们可以清晰的看到登录乐成了,至此我们就可以完善破解,滑动验证问题。代码中宏哥设置的思绪是重复验证,第一次失败,不要着急,程序会自动实验第二次,以此类推,直到验证通过,登录乐成。

5.小结

  好了,今天到这里宏哥就简朴的先容了一下博客园滑动的验证登录,其他的类似的登录机制,你可以照猫画虎即可实现登录了。

 

您的一定就是我提高的动力。若是你感受还不错,就请激励一下吧!记得随手点波  推荐  不要遗忘哦!!!

别忘了点 推荐 留下您来过的痕迹

 

阳泉北站列车时刻表:What?废柴, 模拟上岸,代码控制滑动验证真的很难吗?Are you kidding??? 第2张

,

诚信在线

诚信在线 www.chsjkj.cn携手www.cx11.net合作,期待2019年,创新、务实、奋进。

网友评论

  • (*)

最新评论

  • 欧搏会员开户 2020-06-05 00:06:11 回复

    Allbetwww.czsjhf168.com欢迎进入欧博平台(Allbet Gaming),欧博平台开放欧博(Allbet)开户、欧博(Allbet)代理开户、欧博(Allbet)电脑客户端、欧博(Allbet)APP下载等业务。看完我就是最靓的仔

    1

最近发表

文章归档

站点信息

  • 文章总数:653
  • 页面总数:0
  • 分类总数:8
  • 标签总数:1043
  • 评论总数:252
  • 浏览总数:8137