1. 程式人生 > >極驗驗證碼識別

極驗驗證碼識別

lease threshold 寬高 osi ati self 對比 驗證 pass

很多網站的登陸都有驗證碼一項,而極驗的方案就是應用的非常普遍。更多的場景是在反爬蟲的對抗中,極客驗證碼更是首選。本次目標則是用程序來識別並通過極驗驗證碼的驗證(本文來源於崔慶才<網絡爬蟲實戰>一書,此文只是將此案例做一總結,不喜勿噴)。本次使用的是Python庫是selenium庫,Chrome瀏覽器,並配置好ChromeDriver。極驗驗證碼官網為:https://auth.geetest.com/login/。它是一個專註於提供驗證安全的系統,主要驗證方式是拖動滑塊拼合圖像。若圖像完全拼合,則驗證成功,即表單成功提交,否則需要重新驗證,如圖所示:

1.先明確識別步驟:首先,模擬點擊驗證按鈕,然後識別活動缺口的位置,最後,模擬拖動滑塊。

第一步,我們可以直接利用selienium模擬點擊按鈕。第二步的話,需要用到圖像的相關處理方法。實現一個邊緣檢測算法來找出缺口的位置,而對於這種極驗驗證碼,我們可以利用和原圖對比檢測的方式來識別缺口的位置,因為在沒有滑動滑塊之前,缺口並沒有呈現。我們可以同時獲取兩張圖片。設定一個 對比閾值,然後遍歷兩張圖片,找出相同位置像素RGB差距超過此閾值的像素點,那麽此像素點的位置就是缺口的位置。第三步,其中的坑比較多。極驗驗證碼增加了機器軌跡識別,勻速運動,隨機速度等方法都不能通過驗證,只有完全模擬人的移動軌跡才可以通過驗證。人的運動軌跡一般是先急加速再減速,我們需要模擬這個過程才能成功。

2.有了思路,我們就可以開始用程序來實現它了。大的方面,主要包括這幾個步驟。第一步,初始化,在這裏我們先初始化 一些selenium的 配置及一些參數的配置。第二步,就是模擬點擊了,這裏主要是利用selenium模塊模擬瀏覽器對網頁進行操作。第三步,就該識別缺口的位置了。首先獲取前後兩張圖片,得到其所在位置和寬高,然後獲取整個網頁的截圖,圖片裁切下來即可。最後一步,模擬拖動,經過多次試驗,得出一個結論,那就是完全模擬加速減速的過程通過了驗證。前段作勻加速,後段作勻減速運動,利用物理學的加速度公式即可完成驗證。

3.最後,放上代碼,有需要的小夥伴可以自取,在使用時請註意,需要更改自己的賬號密碼,如果沒有,則需要註冊。

‘‘‘
極驗驗證碼特點:首先點擊按鈕進行智能驗證,如果驗證不通過,則會彈出滑動驗證的窗口,拖動滑塊拼合圖像進行驗證,之後生成三個加密
參數,通過表單提交到後臺,後臺還會進行一次驗證。
識別驗證需要三步:
1.模擬點擊驗證按鈕
2.識別滑動缺口的位置
3.模擬拖動滑塊
‘‘‘
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

EMAIL = ‘[email protected]‘
PASSWORD = ‘‘
BORDER = 6
INIT_LEFT = 60


class CrackGeetest():
def __init__(self):
self.url = ‘https://account.geetest.com/login‘
self.browser = webdriver.Chrome()
self.wait = WebDriverWait(self.browser, 20)
self.email = EMAIL
self.password = PASSWORD

def __del__(self):
self.browser.close()

def get_geetest_button(self):
"""
獲取初始驗證按鈕
:return:
"""
button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, ‘geetest_radar_tip‘)))
return button

def get_position(self):
"""
獲取驗證碼位置
:return: 驗證碼位置元組
"""
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):
"""
獲取網頁截圖
: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, name=‘captcha.png‘):
"""
獲取驗證碼圖片
:return: 圖片對象
"""
top, bottom, left, right = self.get_position()
print(‘驗證碼位置‘, top, bottom, left, right)
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)
email = self.wait.until(EC.presence_of_element_located((By.ID, ‘email‘)))
password = self.wait.until(EC.presence_of_element_located((By.ID, ‘password‘)))
email.send_keys(self.email)
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 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]
threshold = 60
if abs(pixel1[0] - pixel2[0]) < threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs(
pixel1[2] - pixel2[2]) < threshold:
return True
else:
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 + at
v = v0 + a * t
# 移動距離x = v0t + 1/2 * a * t^2
move = v0 * t + 1 / 2 * 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.CLASS_NAME, ‘login-btn‘)))
submit.click()
time.sleep(10)
print(‘登錄成功‘)

def crack(self):
# 輸入用戶名密碼
self.open()
# 點擊驗證按鈕
button = self.get_geetest_button()
button.click()
# 獲取驗證碼圖片
image1 = self.get_geetest_image(‘captcha1.png‘)
# 點按呼出缺口
slider = self.get_slider()
slider.click()
# 獲取帶缺口的驗證碼圖片
image2 = self.get_geetest_image(‘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)

success = self.wait.until(
EC.text_to_be_present_in_element((By.CLASS_NAME, ‘geetest_success_radar_tip_content‘), ‘驗證成功‘))
print(success)

# 失敗後重試
if not success:
self.crack()
else:
self.login()

if __name__ == ‘__main__‘:
crack = CrackGeetest()
crack.crack()
4.到此,整個過程完成,有興趣的小夥伴可以試下喲。

極驗驗證碼識別