破解b站登陆的极验滑块验证码3.0

破解b站登陆的极验滑块验证码

对这个一天消费我四五个小时的破站不搞一搞说得过去吗?

  • 编程这个东西,即使你拿着别人现成的code去写一遍也不代表你的就能跑起来,但是你遇到问题才能学习到,如果没问题反而是最差的结果。

  • 这个代码我参考了崔庆才的网络开发爬虫实战(但说实话里面实用的有点少。我第一本花钱买的实体书就这样的。。。)但还是感谢大佬给出了标准答案

源码在最下面,可以直接拿走

import 的库

对于希望分享给大家的code里面不告诉你import的库真的让小白很头疼哈哈

import time
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from PIL import Image
from io import BytesIO
import base64
ACCOUNT = 'b站账号'
PASSWORD = 'b站密码'

有的没的,学selenium里面碰见的,你也顺便看看呗?

chrome_options = Options()
# chrome_options.add_argument('--headless')  # 无头
# chrome_options.add_argument('--disable-gpu')  # 不加载gpu,规避bug
# chrome_options.add_argument('proxy-server=http://111.11.11.11:1234')  # proxy
chrome_options.add_argument('--no-sandbox')  # 解决DevToolsActivePort文件不存在的报错
# chrome_options.add_argument('window-size=1920x3000')  # 指定浏览器分辨率
# chrome_options.add_argument('blink-settings=imagesEnabled=false')  # 不加载图片, 提升速度

代码部分

初始函数

        self.browser = webdriver.Chrome()
        self.wait = WebDriverWait(self.browser, 10)
        self.ACCOUNT = ACCOUNT
        self.PASSWORD = PASSWORD

得到完整的和残缺的图片, 这里面的结构很让我费解啊哈哈,为什么这个图片能藏在标签里面但是不显示出来(用xpath helper 你就能发现真的在标签里)然后了解到可以通过excute js的方法得到这个,之后的获得图片的我都是用这样的方式,这个return 也是精髓,网上找的好多答案都没有return 而且直接输入在console里还可以返回到正确的内容

        time.sleep(1)
        brokeimg = self.browser.execute_script('return document.getElementsByClassName("geetest_canvas_bg geetest_abso'
                                               'lute")[0].toDataURL("image/png")')[22:]
        fullimg = self.browser.execute_script('return document.getElementsByClassName("geetest_canvas_fullbg geetest_f'
                                              'ade geetest_absolute")[0].toDataURL("image/png")')[22:]
        return brokeimg, fullimg

base64解码加密的图片

        image = base64.decodebytes(image.encode())
        new_image = Image.open(BytesIO(image))
        return new_image

检查像素是否相同,就是判断缺口图片的位置在完整图片的哪里,看过我那个OCR识别验证码的肯定熟悉

        pixel1 = image1.load()[x, y]
        pixel2 = image2.load()[x, y]
        threshold = 60
        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

获取缺口的偏移量,下面的代码你肯定不想听我细讲哈哈

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 left

重点来了,根据偏移量获取移动轨迹,在这里你需要对拉动滑块时候的速度有一个计算,有两种方式 一种是先加速后减速,一种是先拉超过缺口的位置再往回退,这两种方式是因为极验这里使用了机器学习吧应该,如果你是以机器的模式匀速拉动到终点就肯定会过不去,因为人的手速是先快速后慢速,先拉到差不多的位置再慢慢减速对准,这点是真的细

# 移动轨迹
        track = []
        # 当前位移
        current = 0
        # 减速阈值 0.5
        mid = distance*4/5
        # 计算间隔 0.7
        t = 0.2
        # 初速度 10
        v = 0

        while current < distance:
            if current < mid:
                # 加速度为正3
                a = 2
            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))
        print('滑动轨迹为: %s' % track)
        return track

拖动滑块,完成验证,这里会有一个终极大坑,有的人遇得到有的人遇不到,机器问题贼坑,看完代码给你讲

slider = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_slider_button')))
        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()

不同的电脑会在这里遇到问题,如果遇到拖动速度卡顿的问题
请在环境里的selenium/webdriver/common/actions/pointer_input里修改
DEFAULT_MOVE_DURATION = 150 自己调试着改 我的电脑要改到2才能测试通过
整了很久都不明白的问题,被一个大佬解决了,跪了ORZ

最后附上完整源代码,其实我还写了12306的点击验证码破解方式,今天该睡觉了就不整了,下周末再整,嘿嘿。
BTW:后面有时间想把代码附上github,现在能直接抄,到时候去github里抄哈哈

# -*- coding: utf-8 -*-
# Author : Jay
# WritedTime : 2019/12/22 intern ing!
"""
*******************************************************
*   破解geetest滑块验证码3.0                           *
*   调用crack_bili_login_slider_geetest()返回cookie    *
*   使用cookie登陆即可                                 *
*******************************************************
"""
import time
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from PIL import Image
from io import BytesIO
import base64
ACCOUNT = 'b站账号'
PASSWORD = 'b站密码'
chrome_options = Options()
# chrome_options.add_argument('--headless')  # 无头
# chrome_options.add_argument('--disable-gpu')  # 不加载gpu,规避bug
# chrome_options.add_argument('proxy-server=http://111.11.11.11:1234')  # proxy
chrome_options.add_argument('--no-sandbox')  # 解决DevToolsActivePort文件不存在的报错
# chrome_options.add_argument('window-size=1920x3000')  # 指定浏览器分辨率
# chrome_options.add_argument('blink-settings=imagesEnabled=false')  # 不加载图片, 提升速度


class CrackGeetest:
    """
    破解极验滑块3.0,传入出现滑块验证码的网页,返回cookie值
    """
    def __init__(self):
        self.browser = webdriver.Chrome()
        self.wait = WebDriverWait(self.browser, 10)
        self.ACCOUNT = ACCOUNT
        self.PASSWORD = PASSWORD

    def get_captcha(self):
        """
        获取残缺、完整的验证码
        :return: 返回验证码图片
        """
        time.sleep(1)
        brokeimg = self.browser.execute_script('return document.getElementsByClassName("geetest_canvas_bg geetest_abso'
                                               'lute")[0].toDataURL("image/png")')[22:]
        fullimg = self.browser.execute_script('return document.getElementsByClassName("geetest_canvas_fullbg geetest_f'
                                              'ade geetest_absolute")[0].toDataURL("image/png")')[22:]
        return brokeimg, fullimg

    def get_decode_image(self, image):
        """
        解码图片
        :param image: 未解码的图片
        :return: 解码后的图片
        """
        image = base64.decodebytes(image.encode())
        new_image = Image.open(BytesIO(image))
        return new_image

    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 = 60
        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

    def compute_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 left

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

        while current < distance:
            if current < mid:
                # 加速度为正3
                a = 2
            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))
        print('滑动轨迹为: %s' % track)
        return track

    def move_to_gap(self, track):
        slider = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_slider_button')))
        ActionChains(self.browser).click_and_hold(slider).perform()
        for x in track:
            ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform()
            '''
            不同的电脑会在这里遇到问题,如果遇到拖动速度卡顿的问题
            请在环境里的selenium/webdriver/common/actions/pointer_input里修改
            DEFAULT_MOVE_DURATION = 150 自己调试着改 我的电脑要改到2才能测试通过
            整了很久都不明白的问题,被一个大佬解决了
            '''
        time.sleep(0.5)
        ActionChains(self.browser).release().perform()

    def crack_bili_login_slider_geetest(self):
        try:
            self.browser.get("https://passport.bilibili.com/login")
            Input = self.browser.find_element_by_id('login-username')
            Input.send_keys(self.ACCOUNT)
            Input = self.browser.find_element_by_id('login-passwd')
            Input.send_keys(self.PASSWORD)
            Input.send_keys(Keys.ENTER)
            image1, image2 = self.get_captcha()
            image1 = self.get_decode_image(image1)  # 残缺图片
            image2 = self.get_decode_image(image2)  # 完整图片
            gap = self.compute_gap(image2, image1)
            track = self.get_track(gap-8)
            self.move_to_gap(track)
            time.sleep(200)
            '''
            此处编写获取cookie并返回
            '''
        except Exception as e:
            print(e)
        finally:
            self.browser.close()

不明白的请留言
我还是小白,如果异议请直接指出!
a ri ga do go za i shi ma su !
o ne ga i shi ma su !

你可能感兴趣的:(小白学爬虫)