爬虫:滑动验证解决方法及python实现
爬蟲時遇到滑動驗證,基本思路是通過selenium操作瀏覽器,將滑動驗證的原始圖片和缺口圖片進行對比,找出缺口位置,然后在利用selenium模擬拖動滑塊,達到驗證的目的。下面就以豬八戒網為例,進行操作。
一、分析
首先訪問 https://account.zbj.com/login:
?
登陸頁面主要為上圖。
點擊按鈕(div標簽,類名為 geetest_radar_tip)后,出現滑動驗證碼:
?
?
?
??這個滑動驗證圖片并沒有原始圖片,直接出現的就是缺口圖片。而我們要找的就是深色缺口的位置。
觀察圖片標簽,找到? ?<canvas class="geetest_canvas_slice geetest_absolute" width="260" height="160"></canvas>這個標簽,如果把該標簽設置的display屬性設置為none,則驗證圖則會變為下圖:
?
?拼接的小方塊隱藏掉了,這張圖片更容易讓我們與原圖比對。
然后再找到<canvas class="geetest_canvas_fullbg geetest_fade geetest_absolute" height="160" width="260" style="display: none; opacity: 1;"></canvas>這個標簽,將display設置為block:
?
?原圖顯示出來,我們可以將上面兩張圖片的滑動驗證圖片進行截取,比對,即可找到缺口位置。
實現過程中要注意幾點:
1.selenium在加載后,不要立即尋找標簽,因為如果標簽沒有加載完成,會找不到,這樣就會拋出錯誤。
2.截圖的大小可以跟瀏覽器的內顯示的大小不一樣,需要計算瀏覽器顯示大小與截圖大小的比例。
3.進行滑動時,要先加速后減速,如果一直勻速,會被網站識別。
?二、實現
?1、導入相關要用的包:
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 from PIL import Image from six import BytesIO import time from selenium.webdriver import ActionChains?
2.主函數:
if __name__ == '__main__':browser = get_url('https://account.zbj.com/login','11111111111','********') #此函數的定義在第3點time.sleep(1)slice_img_label = browser.find_element_by_css_selector('div.geetest_slicebg') #找到滑動圖片標簽browser.execute_script("document.getElementsByClassName('geetest_canvas_slice')[0].style['display'] = 'none'") #將小塊隱藏full_img_label = browser.find_element_by_css_selector('canvas.geetest_canvas_fullbg') #原始圖片的標簽position = get_position(slice_img_label) #獲取滑動驗證圖片的位置,此函數的定義在第4點screenshot = get_screenshot(browser) # 截取整個瀏覽器圖片,此函數的定義在第5點position_scale = get_position_scale(browser,screenshot) #獲取截取圖片寬高和瀏覽器寬高的比例,此函數的定義在第6點slice_img = get_slideimg_screenshot(screenshot,position,position_scale) #截取有缺口的滑動驗證圖片,此函數的定義在第7點browser.execute_script("document.getElementsByClassName('geetest_canvas_fullbg')[0].style['display'] = 'block'") #在瀏覽器中顯示原圖screenshot = get_screenshot(browser) #獲取整個瀏覽器圖片full_img = get_slideimg_screenshot(screenshot,position,position_scale) # 截取滑動驗證原圖browser.execute_script("document.getElementsByClassName('geetest_canvas_slice')[0].style['display'] = 'block'") #將小塊重新顯示left = compare(full_img,slice_img) #將原圖與有缺口圖片進行比對,獲得缺口的最左端的位置,此函數定義在第8點left = left / position_scale[0] #將該位置還原為瀏覽器中的位置 slide_btn = browser.find_element_by_css_selector('.geetest_slider_button') #獲取滑動按鈕track = get_track(left) #獲取滑動的軌跡,此函數定義在第9點move_to_gap(browser,slide_btn,track) #進行滑動,此函數定義在第10點success = browser.find_element_by_css_selector('.geetest_success_radar_tip') #獲取顯示結果的標簽time.sleep(2)if success.text == "驗證成功":login_btn = browser.find_element_by_css_selector('button.j-login-btn') #如果驗證成功,則點擊登錄按鈕 login_btn.click()else:print(success.text)print('失敗')?
下面是主函數中用到的各個功能性函數:
3..定義訪問頁面的函數:
?
def get_url(url,user,password):browser = webdriver.Chrome()browser.get(url)browser.maximize_window()wait = WebDriverWait(browser,10)wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_radar_btn')))user_input = browser.find_element_by_id('username')pwd_input = browser.find_element_by_id('password')btn = browser.find_element_by_css_selector('.geetest_radar_btn')user_input.send_keys(user)pwd_input.send_keys(password)btn.click()time.sleep(0.5)return browser?
此函數主要是用于啟動Chrome,打開網頁,將用戶名和密碼填入相應位置,并點擊驗證按鈕。
4.獲取滑動驗證圖片在瀏覽器的位置。
使用location是獲取標簽左上角的位置,然后再通過該標簽的大小,即可算出其四個角的位置。
def get_position(img_label):location = img_label.locationsize = img_label.sizetop, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size['width']return (left, top, right, bottom)?
?5.獲取整個瀏覽器的截圖。并從內存進行讀取。?
def get_screenshot(browser):screenshot = browser.get_screenshot_as_png()f = BytesIO()f.write(screenshot)return Image.open(f)?
?
?6.通過對比截圖和瀏覽器寬高的大小,算出換算比例。
由于截圖是有瀏覽器的邊緣的拖拽條,所以瀏覽器的寬度+10px
def get_position_scale(browser,screen_shot):height = browser.execute_script('return document.documentElement.clientHeight')width = browser.execute_script('return document.documentElement.clientWidth')x_scale = screen_shot.size[0] / (width+10)y_scale = screen_shot.size[1] / (height)return (x_scale,y_scale)?
?7.截取有缺口的滑動圖片:
def get_slideimg_screenshot(screenshot,position,scale):x_scale,y_scale = scaleposition = [position[0] * x_scale, position[1] * y_scale, position[2] * x_scale, position[3] * y_scale]return screenshot.crop(position)
?
?8.將原始圖片和有缺口的圖片進行比較:
def compare_pixel(img1,img2,x,y):pixel1 = img1.load()[x,y]pixel2 = img2.load()[x,y]threshold = 50if abs(pixel1[0]-pixel2[0])<=threshold:if abs(pixel1[1]-pixel2[1])<=threshold:if abs(pixel1[2]-pixel2[2])<=threshold:return Truereturn Falsedef compare(full_img,slice_img):left = 0for i in range(full_img.size[0]):for j in range(full_img.size[1]):if not compare_pixel(full_img,slice_img,i,j):return ireturn left?
?
?9.計算出滑動的軌跡,其實就是簡單的s = 1/2*a*t*t的簡單公式。這部分代碼,直接用的崔慶才博主的代碼:
def get_track(distance):"""根據偏移量獲取移動軌跡:param distance: 偏移量:return: 移動軌跡"""# 移動軌跡track = []# 當前位移current = 0# 減速閾值mid = distance * 4 / 5# 計算間隔t = 0.2# 初速度v = 0while current < distance:if current < mid:# 加速度為正 2a = 4else:# 加速度為負 3a = -3# 初速度 v0v0 = v# 當前速度 v = v0 + atv = v0 + a * t# 移動距離 x = v0t + 1/2 * a * t^2move = v0 * t + 1 / 2 * a * t * t# 當前位移current += move# 加入軌跡 track.append(round(move))return track?
?10.進行移動:
def move_to_gap(browser,slider, tracks):"""拖動滑塊到缺口處:param slider: 滑塊:param tracks: 軌跡:return:"""ActionChains(browser).click_and_hold(slider).perform()for x in tracks:ActionChains(browser).move_by_offset(xoffset=x, yoffset=0).perform()time.sleep(0.5)ActionChains(browser).release().perform()?
以上3-10是定義的功能性函數,放在前面,2是主函數,放在后面。運行即可。也可以將其寫為一個類,使用時更為方便。此處,只是為實現功能,所以就沒有進一步進行規范。
轉載于:https://www.cnblogs.com/ohahastudy/p/11493971.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的爬虫:滑动验证解决方法及python实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浏览器输入 URL 之后的链路
- 下一篇: Common Attention Poi