Python 自动登陆哔哩哔哩(2captcha打码平台)

前言

  研究爬虫的各位小伙伴都知道,须要登陆才能获取信息的网站,是比较难爬的,缘由就是在于,如今各大网站为了反爬,都加入了图片验证码,滑动验证码之类的干扰php

  本篇就针对哔哩哔哩的滑动验证码进行讲解和破解web

 

 

关于破解滑动验证到底是本身使用机器学习仍是第三方服务讨论

 

  先说一下我的观点:本人做为一个爬虫老鸟,若是只是为了使用,很是建议使用第三方服务,为何呢,来听我细细分析,json

  如今是2020年了,混IT的都知道,如今大红大紫的热门行业是哪一个,确定都说机器学习,都想入门机器学习,可是不少人还没入门就挂了,这是为何呢,由于入门机器学习,是须要有高数的底子的,可不是之前学一个语言,会经常使用逻辑就能够入门的了,这也是为何到如今为止,依然还有很是大的机器学习人才缺口,再说一下为何本身作爬虫不建议使用机器学习,三个字,玩不起,api

  首先,你须要有大量的数据,而后再有一个不错的主机用于训练,再而后,就是须要你有高数的底子,若是这三个都有,而且学习了机器学习,你才能够勉强破解滑动验证码,而且不敢保证本身训练的准确度,cookie

  这就是我推荐使用第三方接口的缘由,由于第三方接口就是专门作这类机器学习的,它们有强大的人力物力专门作破解各类验证码,而且识别率很是高,如今通常都是90%以上,价格还香,何乐不为了,本身作是头发掉的少仍是加不够多app

  固然,并非说我不让学习机器学习,毕竟如今是一我的工智能时代,若是已有不错的数学基础,而且有很强大兴趣,在工做之余,能够入坑机器学习的,毕竟趋势如此,cors

  本人的观点是,若是是爬虫遇到了滑动验证码,直接使用第三方平台,若是你颇有兴趣,继续需坑机器学习,dom

  本文使用的第三方服务:https://2captcha.com/机器学习

 

  根据本人测试,是目前识别率最高的平台,价格还行,3美圆几百次吧函数

 

所需工具

  En.... 咱们这里不须要 selenium,2captcha打码平台很神奇,咱们只须要 requests 模块就能够啦,

2captcha打码平台参数分析

 

  既然咱们选择了第三方平台,咱们务必要看一下人家的文档,下面咱们就2captcha平台的极验破解,看一下人家的操做

  首先打开人家官网

 

 

 

  嗯...纯英文,我也看不懂..怎么办呢,别着急,我带大家一步一步分析主要功能

 

  登陆帐号

 

 

 

  登陆完成后,会自动跳到主页

 

 

 

 

  红色圈起来的地方表示剩余多少钱,没有钱的话记得要氪金,不然是不能用滴,氪金过程这里就很少作解释了哈,问题不大

  蓝色圈起来的地方表示这是你的惟一key,每次请求要带上这个key的,因此要保管好

 

  进入主题,研究文档

  点击红色圈的地方,API,通常API都是文档,let's go

 

  En....什么玩意..彻底看不懂,别慌,往下滑

 

 

 

  滑动到Rates,咱们能看到一个列表,咱们要解决的就是极验(GeeTest),因此咱们只看GeeTest就行了

  点击GeeTest

  Go

  好了,已经懵逼了,可是,怕什么,咱们有翻译!!!

 

   这里大概整理一下它的意思

  首先,找到目标网站的gt,challenge和api_server三个值,而后,加上其余一些参数发送到 https://2captcha.com/in.php,会返回一个任务ID

  而后等个15秒左右之后,再向 https://2captcha.com/res.php 请求,带上任务ID加上一些其余参数,会返回三个值,返回的三个值+用户名密码等的向目标网站请求,就能够经过验证了

开始行动

  在目标网站上,咱们寻找一下gt,challenge,api_server三个东西,咱们切换到哔哩哔哩找一下

  咱们点击network,刷新网页,从新加载全部请求,crtl+f,搜索challenge,居然发现

combine 这个接口返回的是这个

 

 

 

  居然在 https://passport.bilibili.com/web/captcha/combine?plat=11 请求中 找到了,可是到底之不是这个呢,人家 2captcha文档 说了,一般能够在initGeetest发现他,咱们尝试下

  点击Elements,按ctrl+shift+f全局搜索一下,搜索 initGeetest

  还真有一个,咱们点进去看看

 

  还真有这个,咱们打上断点,再次刷新,匹配一下是否和network里的同样

 

 

 

 

  上面是断点的值,下面是network的值,至少看着同样的,咱们至少能够肯定,有很大关系

  至少咱们肯定了两个值,gt和challenge,还差一个api_server

  咱们随便输入帐号密码点击登陆一下,触发一下极验,在elements中,搜索api_server

 

 

 

  红色圈起来的地方就表示是api_server,基本参数都找齐了

 

  刚才咱们也说了,参数都找齐了,那咱们就该请求打码平台了

  那咱们,就干呐,前面说到,在network中,请求 https://passport.bilibili.com/web/captcha/combine?plat=11  就能够得到gt,challenge,外加一个key

Ok,咱们来请求一下

 

 

  这样,咱们就拿到了gt,challenge

  咱们请求一下打码平台的接口,带上本身参数

  打码平台须要请求两次,第一次返回的是任务ID,第二次才是滑动模块的成功值

 

 

 

:challenge是动态的,其余的是静态的

API_KEY是打码平台的key

 

 

两个函数,咱们就成功的拿到了打码平台返回的值

 

 

  红色圈起来的,就是破解极验的第一个关键参数,这个参数拿到以后呢,就已经跟人家打码平台不要紧啦,咱们只须要带着相关参数,登陆哔哩哔哩就行了,可是这个参数要往哪发呢,在network通过一番查找后,彷佛发现一个和登陆有关的接口

https://passport.bilibili.com/web/login/v2

 

 

 

 

 

  咱们能够看到,红色框圈起来的部分,正式 2captcha平台 返回给咱们的数据,key,正是  https://passport.bilibili.com/web/captcha/combine?plat=11  返回的key,可是password,进行了加密,他是如何加密的呢

 

 

  通过不断的断点,不断地断点.....终于肯定了,密码会通过这个函数进行加密,它本质是 RSA非对称加密 听着就吓人,不慌,盘它,

 

  这个函数逻辑是先请求//passport.bilbilli.com/login?act=get&r="" ,带上一个随机数,而后会返回一个随机hash,和一个公钥key

  公钥key是固定的,而后将随机hash和密码进行加密,发送后他后,后台进行解密

 

   破解代码

 

 

 

 

 

 

  经过上述两个函数,就模拟出了密码,最后,最后,咱们只须要拼接全部参数,请求一下就ok了

 

 

 

 

 

示例效果

  若是帐号密码错误

 

 

 

  若是帐号密码正确

  第一个表示跳转的url,第二个是返回的cookie,之后咱们想干什么,只须要带着这个cookie就行了

完整代码

 

from pprint import pprint
import time
import random
import requests
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5

API_KEY = "be308827049bfeb0c4c222b76e8b1c92"
method = "geetest"
gt = "b6cc0fc51ec7995d8fd3c637af690de3"
# challenge = "0fb2ae2da43962c1f7aec1dd3f9a58fe"
pageurl = "https://passport.bilibili.com/login"
api_server = "api.geetest.com"


def getChallengeAndKey():
    commbine_header = {
        "Accept": "application/json, text/plain, */*",
        "Accept-Encoding": "gzip, deflate, br",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "Connection": "keep-alive",
        # "Cookie": "sid=9qe9dmi7",
        "Host": "passport.bilibili.com",
        "Referer": "https://passport.bilibili.com/login",
        "Sec-Fetch-Mode": "cors",
        "Sec-Fetch-Site": "same-origin",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36"
    }

    commbine_url = "https://passport.bilibili.com/web/captcha/combine?plat=11"
    response_commbine = requests.get(url=commbine_url, headers=commbine_header)
    # print(response_commbine.text)

    # pprint(response_commbine.json())
    key = response_commbine.json().get("data").get("result").get("key")
    challenge = response_commbine.json().get("data").get("result").get("challenge")
    return key, challenge


def get2CaptchaChallengeAndValidateSeccode(challenge):
    captcha_url = f"https://2captcha.com/in.php?key={API_KEY}&method={method}&gt={gt}&challenge={challenge}&pageurl={pageurl}&api_server={api_server}&json=1"
    r = requests.get(captcha_url)
    print(r.json())
    rid = r.json().get("request")

    # print(rid, type(rid))

    time.sleep(15)

    while True:
        re_cpatcha_url = f"https://2captcha.com/res.php?key={API_KEY}&action=get&id={int(rid)}&json=1"
        # print(re_cpatcha_url)
        r2 = requests.get(re_cpatcha_url)
        print(r2.json())
        if r2.json().get("status") == 1:
            geetest_challenge = r2.json().get("request").get("geetest_challenge")
            geetest_validate = r2.json().get("request").get("geetest_validate")
            geetest_seccode = r2.json().get("request").get("geetest_seccode")

            return geetest_challenge, geetest_validate, geetest_seccode

        time.sleep(5)


# 密码加密
def crack_pwd(hash: str, pwd: str):
    key = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjb4V7EidX/ym28t2ybo0U6t0n
6p4ej8VjqKHg100va6jkNbNTrLQqMCQCAYtXMXXp2Fwkk6WR+12N9zknLjf+C9sx
/+l48mjUU8RqahiFD1XT/u2e0m2EN029OhCgkHx3Fc/KlFSIbak93EH/XlYis0w+
Xl69GV6klzgxW6d2xQIDAQAB
-----END PUBLIC KEY-----
"""
    # 注意上述key的格式
    rsakey = RSA.importKey(key)
    cipher = Cipher_pkcs1_v1_5.new(rsakey)  # 生成对象
    new_pwd = hash + pwd
    cipher_text = base64.b64encode(
        cipher.encrypt(new_pwd.encode("utf-8"))
    )  # 对传递进来的用户名或密码字符串加密
    value = cipher_text.decode('utf8')  # 将加密获取到的bytes类型密文解码成str类型
    return value


# 获取key
def get_act():
    act_header = {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate, br",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "Connection": "keep-alive",
        "Cookie": "sid=9qe9dmi7; _uuid=A8F38E21-6734-4291-C4EC-404AEA0294C750293infoc; buvid3=8548F035-99E8-41F8-BDA1-C63065B96FD5155813infoc",
        "Host": "passport.bilibili.com",
        "Referer": "https://passport.bilibili.com/login",
        "Sec-Fetch-Mode": "cors",
        "Sec-Fetch-Site": "same-origin",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36",
        "X-Requested-With": "XMLHttpRequest"
    }
    r1 = random.random()
    c_url = f"https://passport.bilibili.com/login?act=getkey&r={r1}"
    print("url:", c_url)
    response = requests.get(c_url, headers=act_header)

    # print(response.json())
    hash = response.json().get("hash")
    key = response.json().get("key")
    # print(hash)
    # print(key)
    return hash, key


def login_v2():
    login_v2_header = {
        "Accept": "application/json, text/plain, */*",
        "Accept-Encoding": "gzip, deflate, br",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "Connection": "keep-alive",
        # "Cookie": "sid=9qe9dmi7",
        "Host": "passport.bilibili.com",
        "Referer": "https://passport.bilibili.com/login",
        "Sec-Fetch-Mode": "cors",
        "Sec-Fetch-Site": "same-origin",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36"
    }
    login_v2_url = "https://passport.bilibili.com/web/login/v2"
    r1 = requests.post(login_v2_url, headers=login_v2_header, data=login_v2_dict)
    pprint(r1.json())
    print(r1.cookies.get_dict())


if __name__ == '__main__':
    username = "1234"
    password = "1234"

    login_v2_dict = {
        "captchaType": 11,  # ok
        "username": username,  # ok
        # 须要构建 js 获取密码
        "password": "",
        "keep": True,
        # 经过 commbine 获取
        "key": "",
        "goUrl": "",

        # 经过 2captcha 获取
        "challenge": "",
        "validate": "",
        "seccode": ""
    }

    v2_key, challenge = getChallengeAndKey()
    # print(v2_key, challenge)

    geetest_challenge, geetest_validate, geetest_seccode = get2CaptchaChallengeAndValidateSeccode(challenge)

    # print(geetest_challenge)
    # print(geetest_validate)
    # print(geetest_seccode)

    hash, key_public_key = get_act()

    n = crack_pwd(hash, password)

    login_v2_dict["key"] = v2_key
    login_v2_dict["challenge"] = geetest_challenge
    login_v2_dict["validate"] = geetest_validate
    login_v2_dict["seccode"] = geetest_seccode
    login_v2_dict["password"] = n

    print(n)

    print(login_v2_dict)
    login_v2()
相关文章
相关标签/搜索