1. 程式人生 > 實用技巧 >滑塊驗證碼識別

滑塊驗證碼識別

本文是使用極驗滑動驗證碼的官網做的實驗,沒有賬號的可以先註冊一個賬號 ,地址 :https://account.geetest.com/login
  1. 安裝環境
    1. chromedriver 下載地址 可以根據自己chrome版本和系統自行下載
      地址:http://chromedriver.storage.googleapis.com/index.html
      檢視chrome版本 和下載chromedriver頁面:

      將解壓好的檔案放入/usr/local/bin目錄中,由於mac的很多目錄都是隱藏的,所以我們按快捷鍵command+shift+g,在彈出的視窗輸入/usr/local/bin,
      就可以開啟這個目錄,接著將解壓好的驅動放入此目錄即可。
      安裝 selenium
    2. pip install selenium
      

        
    3. 安裝 PIL 圖片處理
      當我們輸入pip insall PIL時候會發現錯誤,沒有這個模組。因為這個模組安裝是以前版本,在命令列輸入 pip install pillow
      pip install pillow
      

        

    4. 測試
      開啟小黑窗
      from selenium import webdriver
      from PIL import Image
      browser = webdriver.Chrome()
      browser.get("http://www.baidu.com")
      

       得到以下結果證明環境沒問題 接下來開始寫程式碼咯


    寫程式碼:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import time
from io import BytesIO
from PIL import Image
from selenium.webdriver import
ActionChains from selenium.common.exceptions import TimeoutException import random EMAIL = '@qq.com' PASSWORD = '密碼' class CrackGeetest(): """ 初始化 """ def __init__(self): self.url = 'https://account.geetest.com/login' self.browser = webdriver.Chrome() self.wait = WebDriverWait(self.browser, 5) self.email = EMAIL self.password = PASSWORD def __del__(self): self.browser.close() def open(self): """ 輸入使用者及密碼 """ self.browser.get(self.url) email_xpath = '//*[@id="base"]/div[2]/div/div[2]/div[3]/div/form/div[1]/div/div/input' email = self.wait.until(EC.presence_of_element_located((By.XPATH, email_xpath))) password_xpath = '//*[@id="base"]/div[2]/div/div[2]/div[3]/div/form/div[2]/div/div[1]/input' password = self.wait.until(EC.presence_of_element_located((By.XPATH, password_xpath))) email.send_keys(self.email) password.send_keys(self.password) def get_geetest_button(self): """ 獲取初始驗證按鈕 返回按鈕物件 """ button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_radar_tip'))) return button def get_position(self): """ 獲取驗證碼位置-為擷取驗證碼準備 返回驗證碼位置元組 """ img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_canvas_img'))) time.sleep(2) location = img.location size = img.size top, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size[ 'width'] return (top, bottom, left, right) def get_screenshot(self): """[summary] 獲取網頁截圖 """ screenshot = self.browser.get_screenshot_as_png() screenshot = Image.open(BytesIO(screenshot)) return screenshot def get_geetest_image(self, name='captcha.png'): """ 獲取驗證碼圖片 返回圖片物件 """ top, bottom, left, right = self.get_position() screenshot = self.get_screenshot() # 通過驗證碼圖片的位置從網頁截圖上擷取驗證碼 captcha = screenshot.crop((left, top, right, bottom)) captcha.save(name) return captcha def get_slider(self): """ 獲取滑塊物件 """ slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_slider_button'))) return slider def get_track(self, distance): """ 根據偏移量獲取移動軌跡 Arguments: distance {[type]} -- 偏移量 """ # 移動軌跡 track = [] # 當前位移 current = 0 # 減速閥值 mid = distance * 7 / 10 # 計算間隔 t = 0.15 # 初速度 v = 0 while current < distance: if current < mid: # 加速度為正 a = 2.1 else: # 加速度為負 a = -4.8 # 初速度v0 v0 = v # 當前速度 v = v0 + at v = v0 + a * t # 移動距離 x = v0t + 1/2*a*t*t move = v0 * t + 1 / 2 * a * t * t # 當前位移 current += move # 加入軌跡 track.append(round(move, 2)) return track def move_to_gap(self, slider, tracks): """[summary] 拖動滑塊到缺口處 動作: 點選且不釋放滑鼠-拖拽圖片到缺口-釋放滑鼠 Arguments: slider {[type]} -- 滑塊 tracks {[type]} -- 軌跡 """ # 點選並按住滑塊 ActionChains(self.browser).click_and_hold(slider).perform() # 移動 for x in tracks: ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform() time.sleep(0.1) # 釋放滑塊 ActionChains(self.browser).release().perform() def login(self): """[summary] 登入 """ submit = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'login-btn'))) submit.click() time.sleep(1) print('登入成功') def is_try_again(self): """[summary] 判斷是否能夠點選重試 """ button_text = self.browser.find_element_by_class_name('geetest_radar_tip_content') text = button_text.text if text == '嘗試過多': button = self.browser.find_element_by_class_name('geetest_reset_tip_content') button.click() def is_success(self): """[summary] 判斷是否成功 """ button_text2 = self.browser.find_element_by_class_name('geetest_success_radar_tip_content') text2 = button_text2.text if text2 == '驗證成功': return 1 return 0 def for_move(self, x_temp): """[summary] 迴圈拖動 """ flag = 0 for i in range(0, 7): gap = random.randint(16, 20) * i + x_temp if gap < 40: continue print('預估計缺口位置: ', gap) self.is_try_again() slider = self.get_slider() track = self.get_track(gap) print('滑動軌跡: ', track) # 拖動滑塊 self.move_to_gap(slider, track) time.sleep(3) if self.is_success(): flag = 1 break return flag def crack(self): """[summary] 驗證 """ try: # 輸入使用者和密碼 self.open() time.sleep(2) # 點選驗證按鈕 button = self.get_geetest_button() button.click() # 獲取驗證碼圖片 image1 = self.get_geetest_image('captcha1.png') flag = 0 while 1: temp = random.randint(0, 2) # 將軌跡劃分為2, 則有1/2的機率 if temp == 0: print('預估左1/2: ') flag = self.for_move(30) else: print('預估右1/2: ') flag = self.for_move(120) if flag == 1: break except TimeoutException as e: self.crack() # 成功,登入 self.login() time.sleep(10) if __name__ == "__main__": crack = CrackGeetest() crack.crack()