1. 程式人生 > >滑動驗證碼破解(selenium+PIL)-嗶哩嗶哩bilibili

滑動驗證碼破解(selenium+PIL)-嗶哩嗶哩bilibili

#本文思路通過selenium模擬瀏覽器空值瀏覽器進行驗證碼的操作,利用PIL圖片處理工具進行對圖片處理,識別到圖片要滑動過去的陰影距離

在這裡插入圖片描述
在這裡插入圖片描述

小知識點:
1、ActionChains方法是捕捉控制滑鼠進行操作,click_and_hold 點選不放,move_by_offset 按座標移動,release 滑鼠釋放
2、距離算出是通過比較兩張圖片的色值rgb,陰影部分的差值大概在60以上得出(有小技巧是需要先排除其他干擾)

在這裡插入圖片描述

import time
import random
import re
from PIL import Image
from PIL import ImageGrab
from selenium import webdriver
from selenium.webdriver import ActionChains

EMAIL = '賬戶****'
PASSWORD = '密碼*******'

class Bilibili():
    def __init__(self):
        self.url = 'https://passport.bilibili.com/login'
        self.browser = webdriver.Chrome()
        self.browser.maximize_window()
        self.email = EMAIL
        self.password = PASSWORD

    def login(self):
        self.browser.get(self.url)
        time.sleep(5)
        self.browser.find_element_by_id('login-username').send_keys(self.email)
        time.sleep(random.random() * 10)
        self.browser.find_element_by_id('login-passwd').send_keys(self.password)
        time.sleep(random.random() * 10)
        # 擷取驗證圖片1
        image = ImageGrab.grab()
        slider = self.browser.find_element_by_class_name('gt_slider_knob')
        ActionChains(self.browser).release(slider).perform()
        time.sleep(1)
        self.browser.save_screenshot('big.png') #只是截圖瀏覽器視窗內容
        img1 =Image.open('big.png')
        img1 = img1.crop((983, 210, 1273, 370))  #(left, top, left+width, top+height)這幾個數值表示
        img1.save('1.png')
        image1 = Image.open('1.png')
        image1_array = image1.load()
        # 擷取驗證圖片2
        ActionChains(self.browser).click_and_hold(slider).perform()
        # screenshot_2 = self.browser.get_screenshot_as_png()
        time.sleep(1)
        self.browser.save_screenshot('big2.png')
        img2 = Image.open('big2.png')
        img2 = img2.crop((983, 210, 1273, 370))
        img2.save('2.png')
        image2 = Image.open('2.png')
        image2_array = image2.load()
        # 判斷需要滑動的距離
        # 滑動的部分與陰影部分的差值大概在60以上80以下,因此採用如下判斷
        #0,1,2是分別對應rgb色值
        #截圖下來大小290*160,下面數值範圍選擇考慮到排除其他影響因素就只留滑塊陰影部分
        for i in range(70, 270):
            for j in range(20, 100):
                if image1_array[i, j][0] - image2_array[i, j][0] > 60 and image1_array[i, j][1] - image2_array[i, j][1] > 60 and image1_array[i, j][2] - image2_array[i, j][2] > 60:
                    border = i
        print(border)
        # 構造滑動列表
        track = []
        current = 0
        #其實64這個值大概準確有時出錯,因為他滑塊其實位置可能會有偏差,所以下面重新呼叫多次嘗試
        while current < border - 64:
            track.append(1)
            current += 1
        print(track)
        # 滑動滑塊
        # 直接勻速滑動肯定通不過,先加速後減速效果也不是很好。
        # 但是這種簡單的方法,每移動一次隨機停頓0-1秒之間騙過了極驗,通過率很高
        #click_and_hold 點選不放,move_by_offset 按座標移動,release 滑鼠釋放
        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(random.random() / 100)
        time.sleep(random.random())
        ActionChains(self.browser).release().perform()
        time.sleep(5)
       
        rsp = self.browser.page_source

    # 已登入的頁面有‘大會員’選單欄,未登入頁面沒有,
    # 所以用正則判斷以下。 如果正則未匹配到,證明登入失敗,嘗試再次登入
        if re.findall(r'大會員', rsp, re.S):
            print('Login successfully ...')
        else:
            print('Try again ...')
            self.login()


if __name__ == '__main__':
    b = Bilibili()
    b.login()