滑動驗證碼破解(selenium+PIL)-嗶哩嗶哩bilibili
阿新 • • 發佈:2018-12-30
#本文思路通過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()