爬蟲模擬登錄破解無原圖滑動驗證碼: https://www.cnblogs.com/98WDJ/p/11050559.html
需求:部分網站在頻繁的使用之后,會彈出滑塊驗證碼(極驗)。有別於過去,現在的原圖並不會出現,因此較過去的思路轉變為以下:
1、截取帶缺口的圖片;
2、尋找原圖,並截圖;
3、比較兩張圖片,尋找到缺口位置距離;
4、計算運動過程,並驅動瀏覽器移動滑塊。
參考鏈接基本提供了1-3步的實現,第4步存在被識別為機器操作,需要進行更新(修正以后,目前成功率應該有50%以上),記錄如下。
一、啟動瀏覽器,配置option,以防被識別為自動化。
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait from selenium.common.exceptions import TimeoutException from selenium.webdriver import ActionChains from PIL import Image import numpy as np import pandas as pd import time # 配置瀏覽器 options = webdriver.ChromeOptions() # 此步驟很重要,設置為開發者模式,防止被各大網站識別出來使用了Selenium options.add_experimental_option('excludeSwitches', ['enable-automation'])
二、獲取兩張圖片進行比較,通過網頁分析發現。該標簽,當display=block,opacity=1時,顯示的為原圖。

# 獲取第一個圖 img_name1 = r'../data/png/captcha2.png' img_name2 = r'../data/png/captcha2_src.png' img = wait.until(EC.presence_of_element_located((By.XPATH,'//canvas[@class="geetest_canvas_slice geetest_absolute"]'))) img.screenshot(img_name1) # 獲取原圖 browser.execute_script("var x=document.getElementsByClassName('geetest_canvas_fullbg geetest_fade geetest_absolute')[0];" "x.style.display='block';" "x.style.opacity=1" ) img = wait.until(EC.presence_of_element_located((By.XPATH,'//canvas[@class="geetest_canvas_slice geetest_absolute"]'))) img.screenshot(img_name2) # 變回來 browser.execute_script("var x=document.getElementsByClassName('geetest_canvas_fullbg geetest_fade geetest_absolute')[0];" "x.style.display='none';" "x.style.opacity=0" )
三、計算兩張圖片差異,通過rgb一定的缺值進行判斷缺口。
# 如何能找到滑塊的位置 def get_distance(img1,img2): start_x=60#初始X threhold=60#閾值 for x in range(start_x,img1.size[0]): for y in range(img1.size[1]): rgb1=img1.load()[x,y] rgb2=img2.load()[x,y] res1=abs(rgb1[0]-rgb2[0]) res2=abs(rgb1[1]-rgb2[1]) res3=abs(rgb1[2]-rgb2[2]) if not (res1<threhold and res2<threhold and res3<threhold): return x-7#測試后-7可以提高成功率
四、計算模擬移動,根據自身的挪動特點,我一般的移動操作分為三個階段(可根據自身特點進行設計)。
1:點擊滑塊以后,緩慢移動一下。約移動3次。
2:快速移動到缺口附件。大概0.3s。
3:到了缺口附近以后,緩慢靠近,然后在缺口處停留大概0.5秒以后釋放。
# 將整個過程分為3段,總時長大概是1.2-1.6秒 # 第一段是啟動階段,第一次點擊的時候,總會比較拘謹,慢速啟動,大概消費t2(0.3)秒,s2為分段數 # 第二段則是很快到達缺口附近,大概剩余d3(5)距離處 # 第三段是緩慢對接,最后停在上面0.5秒 def get_tracks(distance,s1 = 2,t2 = 0.3,s2 = 3,d3 = 5): # 計算d1移動過程 dtemp = 0 track1 = [] for i in range(s1): t = np.random.randint(low = 1, high=3) track1.append(t) dtemp = dtemp + t # 計算d2距離 distance =distance - dtemp - d3 track2 = [] a = 2 * distance /(t2 ** 2) dtemp = 0 for i in range(s2): # 計算每段行走 ttemp1 = t2/s2 * (i + 1) ttemp2 = t2/s2 * i t = int(0.5 * a * (ttemp1 ** 2) - 0.5 * a * (ttemp2 ** 2) ) track2.append(t) dtemp = dtemp + t #由於取整了,可以存在一點誤差,調整d3 d3 = distance - dtemp + d3 print(d3) track3 = [] s = 0 while s < d3: t = np.random.randint(low = 1, high=3) if s + t >= d3: track3.append(d3 - s) break else: s = s + t track3.append(t) return {"track1": track1, 'track2': track2, 'track3': track3}
%%time # 計算路徑,不行,這個會被識別為計算機 #獲得滑塊元素 geetest_slider_button=browser.find_element_by_class_name('geetest_slider_button') #獲得距離 img1 = Image.open(img_name1) img2 = Image.open(img_name2) distance=get_distance(img1,img2) #獲得步數 tracks_dic=get_tracks(distance,s1 = 2,t2 = 0.2,s2 = 3,d3 = 5) #點擊並按住 ActionChains(driver).click_and_hold(geetest_slider_button).perform() track1=tracks_dic['track1'] track2=tracks_dic['track2'] track3=tracks_dic['track3']
最后,遍歷執行動作鏈。
%%time # 執行 ActionChains(browser).click_and_hold(geetest_slider_button).perform() # 執行第一步 for t in track1: ActionChains(browser).move_by_offset(xoffset=t,yoffset=0).perform() #停頓一會,更像人 time.sleep(0.2) for t in track2: ActionChains(browser).move_by_offset(xoffset=t,yoffset=0).perform() for t in track3: ActionChains(browser).move_by_offset(xoffset=t,yoffset=0).perform() time.sleep(0.5) # 松開 ActionChains(browser).release(geetest_slider_button).perform()
