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()
相關文章
相關標籤/搜索