滑動驗證碼破解 | Selenium模擬登錄博客園

 

思路:web

 

(1)打開登陸頁面,並輸入用戶名和密碼,點擊登陸按鈕,彈出驗證碼圖片;chrome

 

(2)獲取2張驗證碼圖片,帶缺口和不帶缺口;canvas

 

(3)獲取缺口位置。遍歷帶缺口的圖片和不帶缺口的圖片的每一個像素,利用 is_pixel_equal() 方法判斷兩張圖片同一位置的像素是否相同。比較兩張圖 RGB 的絕對值是否均小於定義的閾值 thresold。若是絕對值均在閾值以內,則表明像素點相同,繼續遍歷。不然表明不相同的像素點,就是缺口的位置。

經過對比兩張圖片能夠發現,兩張圖片有兩處明顯不一樣的地方:一個是待拼合的滑塊,一個是缺口。滑塊的位置會出如今左邊位置,缺口會出如今與滑塊同一水平線的位置,因此缺口通常會在滑塊的右側。若是要尋找缺口,直接從滑塊右側尋找便可。這裏直接設置遍歷的起始橫座標爲60,也就是從滑塊的右側開始識別,這樣識別出的結果就是缺口的位置。app

 

(4)移動滑塊至缺口位置ide

import time from io import BytesIO from PIL import Image from selenium import webdriver from selenium.webdriver import ActionChains from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC USERNAME = 'username' PASSWORD = 'password' BORDER = 6

class CrackGeetest(): def __init__(self): self.url = 'https://passport.cnblogs.com/user/signin' self.browser = webdriver.Chrome('D:\download\chromedriver.exe') self.wait = WebDriverWait(self.browser, 20) self.username = USERNAME self.password = PASSWORD def __del__(self): self.browser.close() def get_login_button(self): """ 獲取登陸按鈕,調出極驗驗證碼 :return: 登陸按鈕對象 """
        #button_login = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'button')))
        button_login = self.wait.until(EC.element_to_be_clickable((By.ID, 'submitBtn'))) return button_login def get_geetest_button(self): """ 獲取初始驗證按鈕,即點擊按鈕進行驗證 :return: 按鈕對象 """ button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_slider_button'))) return button def get_position(self, flag): """ 獲取驗證碼位置 :return: 驗證碼位置元組 """ img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_canvas_img'))) fullbg = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, "geetest_canvas_fullbg"))) time.sleep(2) if flag: self.browser.execute_script( "arguments[0].setAttribute(arguments[1], arguments[2])", fullbg, "style", "") print("獲取不帶缺口的圖片成功") else: self.browser.execute_script( "arguments[0].setAttribute(arguments[1], arguments[2])", fullbg, "style", "display: none") print("獲取帶缺口的圖片成功") 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, size) def get_screenshot(self): """ 獲取網頁截圖 :return: 截圖對象 """ screenshot = self.browser.get_screenshot_as_png() screenshot = Image.open(BytesIO(screenshot)) return screenshot def get_slider(self): """ 獲取滑塊 :return: 滑塊對象 """ slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_slider_button'))) return slider def get_geetest_image(self, flag, name='captcha.png'): """ 獲取驗證碼圖片 :return: 圖片對象 """ top, bottom, left, right, size= self.get_position(flag) print('驗證碼位置', top, bottom, left, right, size) screenshot = self.get_screenshot() # 根據驗證碼圖像位置獲取驗證碼圖像
        captcha = screenshot.crop((left, top, right,bottom)) #captcha.save(name)
        return captcha def open(self): """ 打開網頁輸入用戶名密碼 :return: None """ self.browser.get(self.url) username = self.wait.until(EC.presence_of_element_located((By.ID, 'LoginName'))) password = self.wait.until(EC.presence_of_element_located((By.ID, 'Password'))) username.send_keys(self.username) password.send_keys(self.password) def get_gap(self, image1, image2): """ 獲取帶缺口的偏移量 :param image1: 不帶缺口的圖片 :param image2: 帶缺口的圖片 :return: """ left = 60
        for i in range(left, image1.size[0]): for j in range(image1.size[1]): if not self.is_pixel_equal(image1, image2, i, j): # left = i
                    # return left
                    return i return left def is_pixel_equal(self, image1, image2, x, y): """ 判斷兩個像素是否相同 :param image1: 圖片1 :param image2: 圖片2 :param x: 位置x :param y: 位置y :return: 像素是否相同 """
        # 取兩個圖片的像素點
        pixel1 = image1.load()[x,y] pixel2 = image2.load()[x,y] #print("piexl1", pixel1, "piexl2", pixel2)
        threshold = 60
        if abs(pixel1[0] - pixel2[0]) < threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs( pixel1[2] - pixel2[2]) < threshold: #print("True")
            return True else: #print("False")
            return False def get_track(self, distance): """ 根據偏移量獲取移動軌跡 :param distance: 偏移量 :return: 移動軌跡 """
        # 移動軌跡
        track = [] # 當前位移
        current = 0 # 減速閾值
        mid = distance * 4 / 5
        # 計算間隔
        t = 0.2
        # 初速度
        v = 0 while current < distance: if current < mid: # 加速度爲正2
                a = 2
            else: # 加速度爲負3
                a = -3
            # 初速度v0
            v0 = v # 當前速度v = v0 + a * t
            v = v0 + a * t # 移動距離 x = v0*t + 1/2 * a * t^2
            move = v0 * t + 0.5 * a * t * t # 當前位移
            current += move # 加入軌跡
 track.append(round(move)) return track def move_to_gap(self, slider, track): """ 拖動滑塊到缺口處 :param slider: 滑塊 :param track: 軌跡 :return: """ 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(0.5) ActionChains(self.browser).release().perform() def login(self): """ 登陸 :return: None """ submit = self.wait.until(EC.element_to_be_clickable((By.ID, 'signin'))) submit.click() time.sleep(10) print('登陸成功') def crack(self): # 輸入用戶名和密碼
 self.open() # 點擊登陸按鈕,調出驗證按鈕
        login_button = self.get_login_button() login_button.click() # 獲取驗證碼圖片,不帶缺口
        image1 = self.get_geetest_image(True, 'captcha1.png') # 點按呼出缺口圖片,獲取滑塊
        slider = self.get_slider() # slider.click() # 如今不須要點擊滑塊便可呼出缺口圖片
        # 獲取帶缺口的驗證碼圖片
        image2 = self.get_geetest_image(False, 'captcha2.png') # 獲取缺口位置
        gap = self.get_gap(image1, image2) print('缺口位置', gap) # 減去缺口位移
        gap -= BORDER # 獲取移動軌跡
        track = self.get_track(gap) print('滑動軌跡', track) # 拖動滑塊
 self.move_to_gap(slider, track) try: success = self.wait.until( EC.text_to_be_present_in_element((By.CLASS_NAME, 'geetest_success_radar_tip_content'), '驗證成功')) print(success) #self.login()
        except Exception: self.crack() if success: self.login()
if __name__ == '__main__': crack = CrackGeetest() crack.crack()
相關文章
相關標籤/搜索