selenium滑塊驗證


使用selenium模擬登錄解決滑塊驗證問題

本次主要是使用selenium模擬登錄網頁端的TX新聞,本來最開始是模擬請求的,但是某一天突然發現,部分賬號需要經過滑塊驗證才能正常登錄,如果還是模擬請求,需要的參數太多了,找的心累。不過好在TX的滑塊驗證是他們自己開發的,沒有極驗那么復雜,當然相反的,想要模擬就得自己去一點點探索了,畢竟對極驗滑塊的破解,網上已經可以找到現成的代碼來用了。下面說一下模擬的實現過程和我遇見的問題。

1.登錄入口

我是通過點擊打開鏈接來當做登錄入口的

部分代碼實現:

driver = webdriver.Chrome()
 
driver.get(url)

2.點擊“賬號密碼登錄”

selenium可以實現對網頁元素的定位,我這里是通過id屬性來定位“帳號密碼登錄”按鈕的。這里需要注意的是,有時候可能會因為網絡不好等問題導致加載登錄入口頁會很慢,所以在點擊“帳號密碼登錄”按鈕前,需要做一個判斷:判斷代表“帳號密碼登錄”的HTML元素是否已經加載完成。

“賬號密碼登錄”按鈕的id屬性截圖:

部分代碼實現

element = WebDriverWait(driver, 5, 0.5).until(
 
EC.presence_of_element_located((By.ID, "switcher_plogin")))
 
# from selenium.webdriver.common.by import By element.click()

  

3.輸入賬號、密碼並點擊登錄

這一步比較簡單,直接上代碼:

driver.find_element_by_id('u').send_keys('123456') # 輸入用戶名
 
driver.find_element_by_id('p').send_keys('ccccc') # 輸入密碼
 
driver.find_element_by_id('login_button').click() # 點擊登錄

  

4.滑塊驗證過程

1)簡要說明

因為主要目的就是為了模擬滑塊驗證,所以在輸入用戶名和密碼的時候直接選擇輸入“123456”和“ccccc”,這樣就必然會跳到滑塊驗證的頁面:

接下來的問題就是如何模擬滑動的過程。這里首先要說一下,經過多次測試發現,TX的滑塊驗證每次需要拖動的距離是有一定范圍的,“缺口”部分的位置基本上都在靠右側的一面,不像極驗的滑塊驗證,“缺口”部分可能出現在任意的位置,這樣在實現“滑動”過程前,就必須判斷每次滑動的距離是多少,具體可以看看這里學習一下大神們都是如何實現極驗滑塊驗證的。所以,對於TX的滑塊驗證,只要設置一個大概的距離“模擬滑動”即可,失敗的時候可以通過增減移動距離進行重試,后面會進一步說明。

2)為什么找不到“藍色滑塊”

前面已經點擊了“登錄”並跳轉到“安全驗證”的頁面,接着就是去模擬“拖動”截圖中的“藍色滑塊”,所以首先要告訴driver,代表“藍色滑塊”的html元素是什么。代表“藍色滑塊”的html元素截圖:

通過上面的截圖可以知道,id值為"tcaptcha_drag_button"的div標簽代表的就是“藍色滑塊”,所以最開始我是直接嘗試去拖動它,但是這時候發現報錯了,部分截圖如下:

報錯的原因很明顯,在當前得到的所有html元素中,找不到id值為"tcaptcha_drag_button"的div標簽。這是為什么?

3)切換frame

為什么出現上面的問題?通過查找相關的資料才知道,在跳轉到“安全驗證”的頁面的時候,“進入”了一個新的frame,可以理解為,在“登錄頁面”嵌套了一個“驗證頁面”,而當前的driver加載的html元素全部都是“登錄頁面”的,想要找到並拖動“藍色滑塊”,就要先切換到“驗證頁面”,這里通過driver.switch_to方法實現:

iframe = driver.find_element_by_xpath('//iframe') # 找到“嵌套”的iframe
 
driver.switch_to.frame(iframe)     # 切換到iframe

4)模擬拖動

切換到iframe之后,就可以通過driver.find_element_by_id('tcaptcha_drag_button')找到“藍色滑塊”並拖動它了。拖動操作會用到selenium.webdriver的ActionChains類,部分代碼如下:

button = driver.find_element_by_id('tcaptcha_drag_button')    # 找到“藍色滑塊”
 
action = ActionChains(driver)            # 實例化一個action對象
 
action.click_and_hold(button).perform()  # perform()用來執行ActionChains中存儲的行為
 
action.reset_actions()
 
action.move_by_offset(180, 0).perform()  # 移動滑塊

  

5)構造移動軌跡

為了使拖動過程模擬的更“真實”,可以構造一個滑動軌跡,我這里也是參考了別人的代碼看這里,簡單實現了一下,實際上TX新聞的滑塊驗證對這方面好像要求不是很嚴格:

def get_track(distance):
 
track = []
 
current = 0
 
mid = distance * 3 / 4
 
t = 0.2
 
v = 0
 
while current < distance:
 
if current < mid:
 
a = 2
 
else:
 
a = -3
 
v0 = v
 
v = v0 + a * t
 
move = v0 * t + 1 / 2 * a * t * t
 
current += move
 
track.append(round(move))
 
return track

  

6)如何確定已經“驗證成功”了

接下來的問題就是,我如何告訴程序,已經“驗證成功”了呢?經過測試發現,當拖動滑塊完成拼圖“驗證成功”后,網頁又從“安全驗證”的頁面又跳回了“登錄頁面”,滑動前截圖:

 

滑動驗證成功的截圖:

 

成功后跳轉回“登錄”頁面:

 

通過上面的截圖我們可以知道,在“驗證通過”之前,在“安全驗證”頁面我們一直可以看到“拖動下方滑塊完成拼圖”的文字提示,也就是說,如果驗證沒有通過,那么在當前的所有html元素中,我們是可以找到文本為“拖動下方滑塊完成拼圖”的標簽的:

通過截圖可以知道,該標簽的class為"tcaptcha-title",通過driver.find_element_by_class_name('tcaptcha-title').text來判斷驗證是否成功。

7)重試

前面說了,我們可以通過提前設置一個“可能的”值當初始距離來移動滑塊,如果移動的距離“過長”,就減小該值當做下次移動的距離,所以可以加一個while循環。以上過程實現的完整代碼如下:

# encoding=utf8
 
 
 
from time import sleep
 
from selenium import webdriver
 
from selenium.webdriver import ActionChains
 
from selenium.webdriver.common.by import By
 
from selenium.webdriver.support import expected_conditions as EC
 
from selenium.webdriver.support.wait import WebDriverWait
 
 
 
url = 'https://xui.ptlogin2.qq.com/cgi-bin/xlogin?&low_login=0&appid=636014201&target=self&border_radius=1&maskOpacity=40&s_url=http%3A//www.qq.com/qq2012/loginSuccess.htm'
 
 
 
def get_track(distance):
 
track = []
 
current = 0
 
mid = distance * 3 / 4
 
t = 0.2
 
v = 0
 
while current < distance:
 
if current < mid:
 
a = 2
 
else:
 
a = -3
 
v0 = v
 
v = v0 + a * t
 
move = v0 * t + 1 / 2 * a * t * t
 
current += move
 
track.append(round(move))
 
return track
 
 
 
def main():
 
driver = webdriver.Chrome()
 
driver.set_window_position(900, 10)
 
driver.get(url)
 
# 檢測id為"switcher_plogin"的元素是否加在DOM樹中,如果出現了才能正常向下執行
 
element = WebDriverWait(driver, 5, 0.5).until(
 
EC.presence_of_element_located((By.ID, "switcher_plogin"))
 
)
 
element.click()
 
 
 
sleep(1)
 
# 輸入用戶名和密碼
 
driver.find_element_by_id('u').clear()
 
driver.find_element_by_id('u').send_keys('123456')
 
driver.find_element_by_id('p').clear()
 
driver.find_element_by_id('p').send_keys('ccccc')
 
sleep(1)
 
# 點擊登錄
 
driver.find_element_by_id('login_button').click()
 
 
 
sleep(5)
 
 
 
# 切換iframe
 
try:
 
iframe = driver.find_element_by_xpath('//iframe')
 
except Exception as e:
 
print 'get iframe failed: ', e
 
sleep(2) # 等待資源加載
 
driver.switch_to.frame(iframe)
 
 
 
# 等待圖片加載出來
 
WebDriverWait(driver, 5, 0.5).until(
 
EC.presence_of_element_located((By.ID, "tcaptcha_drag_button"))
 
)
 
try:
 
button = driver.find_element_by_id('tcaptcha_drag_button')
 
except Exception as e:
 
print 'get button failed: ', e
 
 
 
sleep(1)
 
# 開始拖動 perform()用來執行ActionChains中存儲的行為
 
flag = 0
 
distance = 195
 
offset = 5
 
times = 0
 
while 1:
 
action = ActionChains(driver)
 
action.click_and_hold(button).perform()
 
action.reset_actions() # 清除之前的action
 
print distance
 
track = get_track(distance)
 
for i in track:
 
action.move_by_offset(xoffset=i, yoffset=0).perform()
 
action.reset_actions()
 
sleep(0.5)
 
action.release().perform()
 
sleep(5)
 
 
 
# 判斷某元素是否被加載到DOM樹里,並不代表該元素一定可見
 
try:
 
alert = driver.find_element_by_class_name('tcaptcha-title').text
 
except Exception as e:
 
print 'get alert error: %s' % e
 
alert = ''
 
if alert:
 
print u'滑塊位移需要調整: %s' % alert
 
distance -= offset
 
times += 1
 
sleep(5)
 
else:
 
print '滑塊驗證通過'
 
flag = 1
 
driver.switch_to.parent_frame()    # 驗證成功后跳回最外層頁面
 
break
 
 
 
sleep(2)
 
driver.quit()
 
print "finish~~"
 
return flag
 
 
 
if __name__ == '__main__':
 
main()

  

5.小結

其實上面的代碼還可以進一步“優化”。例如,當嘗試三次滑動后如果仍然沒有“驗證成功”,就應該主動跳回“登錄”頁面,重新輸入賬號密碼登錄,進入下一次驗證過程,而不是無休止的進行“滑塊驗證”。除此之外,以上只是對“滑塊驗證”部分進行了分析和模擬,實際情況是,通過了“滑塊驗證”后,有可能賬號或密碼錯誤了,這時候是不是應該重新輸入賬號密碼進入新一輪驗證過程呢?

所以,以上代碼還有待繼續完善,也歡迎看到這篇博文的人多多指正不足之處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM