日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python3 爬虫学习笔记 C13【验证码对抗系列 — 滑动验证码】

發布時間:2023/12/10 python 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python3 爬虫学习笔记 C13【验证码对抗系列 — 滑动验证码】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Python3 爬蟲學習筆記第十三章 —— 【驗證碼對抗系列 — 滑動驗證碼】

文章目錄

  • 【13.1】關于滑動驗證碼
  • 【13.2】滑動驗證碼攻克思路
  • 【13.3】模擬登錄 bilibili — 總體思路
  • 【13.4】主函數
  • 【13.5】初始化函數
  • 【13.6】登錄函數
  • 【13.7】驗證碼元素查找函數
  • 【13.8】元素可見性設置函數
  • 【13.9】驗證碼截圖函數
  • 【13.10】滑動函數
  • 【13.11】計算滑塊移動距離函數
  • 【13.12】像素判斷函數
  • 【13.13】構造移動軌跡函數
  • 【13.14】模擬拖動函數
  • 【13.15】效果實現動圖
  • 【13.16】完整代碼


【13.1】關于滑動驗證碼

滑動驗證碼屬于行為式驗證碼,需要通過用戶的操作行為來完成驗證,一般是根據提示用鼠標將滑塊拖動到指定的位置完成驗證,此類驗證碼背景圖片采用多種圖像加密技術,且添加了很多隨機效果,能有效防止OCR文字識別,另外,驗證碼上的文字采用了隨機印刷技術,能夠隨機采用多種字體、多種變形的實時隨機印刷,防止暴力破解;斗魚、嗶哩嗶哩、淘寶等平臺都使用了滑動驗證碼


【13.2】滑動驗證碼攻克思路

利用自動化測試工具 Selenium 直接模擬人的行為方式來完成驗證,首先要分析頁面,想辦法找到滑動驗證碼的完整圖片、帶有缺口的圖片和需要滑動的圖片,通過對比原始的圖片和帶滑塊缺口的圖片的像素,像素不同的地方就是缺口位置,計算出滑塊缺口的位置,得到所需要滑動的距離,最后利用 Selenium 進行對滑塊的拖拽,拖拽時要模仿人的行為,由于有個對準過程,所以是先快后慢,勻速移動、隨機速度移動都不會成功

以下以嗶哩嗶哩為例來做模擬登錄練習


【13.3】模擬登錄 bilibili — 總體思路

首先使用 Selenium 模擬登陸 bilibili,自動輸入賬號密碼,查找到登陸按鈕并點擊,使其出現滑動驗證碼,此時分析頁面,滑動驗證組件是由3個 canvas 組成,分別代表完整圖片、帶有缺口的圖片和需要滑動的圖片,3個 canvas 元素包含 CSS display 屬性,display:block 為可見,display:none 為不可見,分別獲取三張圖片時要將其他兩張圖片設置為 display:none,獲取元素位置后即可對圖片截圖并保存,通過圖片像素對比,找到缺口位置即為滑塊要移動的距離,隨后構造滑動軌跡,按照先加速后減速的方式移動滑塊完成驗證。

整個程序包含的函數:

def init(): 初始化函數,定義全局變量 def login(): 登錄函數,輸入賬號密碼并點擊登錄 def find_element(): 驗證碼元素查找函數,查找三張圖的元素 def hide_element(): 設置元素不可見函數 def show_element(): 設置元素可見函數 def save_screenshot(): 驗證碼截圖函數,截取三張圖并保存 def slide(): 滑動函數 def is_pixel_equal(): 像素判斷函數,尋找缺口位置 def get_distance(): 計算滑塊移動距離函數 def get_track(): 構造移動軌跡函數 def move_to_gap(): 模擬拖動函數

整個程序用到的庫:

from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver import ActionChains import time import random

【13.4】主函數

if __name__ == '__main__':init()login()find_element()slide()

【13.5】初始化函數

def init():global url, browser, username, password, waiturl = 'https://passport.bilibili.com/login'path = r'F:\PycharmProjects\Python3爬蟲\chromedriver.exe'chrome_options = Options()chrome_options.add_argument('--start-maximized')browser = webdriver.Chrome(executable_path=path, chrome_options=chrome_options)username = '155********'password = '***********'wait = WebDriverWait(browser, 20)

global 關鍵字定義了全局變量,隨后是登錄頁面url、谷歌瀏覽器驅動的目錄path、實例化 Chrome 瀏覽器、設置瀏覽器分辨率最大化、用戶名、密碼、WebDriverWait() 方法設置等待超時


【13.6】登錄函數

def login():browser.get(url)user = wait.until(EC.presence_of_element_located((By.ID, 'login-username')))passwd = wait.until(EC.presence_of_element_located((By.ID, 'login-passwd')))user.send_keys(username)passwd.send_keys(password)login_btn = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'a.btn.btn-login')))time.sleep(random.random() * 3)login_btn.click()

等待用戶名輸入框和密碼輸入框對應的 ID 節點加載出來,分析頁面可知,用戶名輸入框 id="login-username",密碼輸入框 id="login-passwd",獲取這兩個節點,調用 send_keys() 方法輸入用戶名和密碼,隨后獲取登錄按鈕,分析頁面可知登錄按鈕 class="btn btn-login",隨機產生一個數并將其擴大三倍作為暫停時間,最后調用 click() 方法實現登錄按鈕的點擊


【13.7】驗證碼元素查找函數

def find_element():c_background = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_bg.geetest_absolute')))c_slice = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_slice.geetest_absolute')))c_full_bg = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_fullbg.geetest_fade.geetest_absolute')))hide_element(c_slice)save_screenshot(c_background, 'back')show_element(c_slice)save_screenshot(c_slice, 'slice')show_element(c_full_bg)save_screenshot(c_full_bg, 'full')

我們要獲取驗證碼的三張圖片,分別是完整的圖片、帶有缺口的圖片和需要滑動的圖片,分析頁面代碼,這三張圖片是由 3 個 canvas 組成,3 個 canvas 元素包含 CSS display 屬性,display:block 為可見,display:none 為不可見,在分別獲取三張圖片時要將其他兩張圖片設置為 display:none,這樣做才能單獨提取到每張圖片,定位三張圖片的 class 分別為:帶有缺口的圖片(c_background):geetest_canvas_bg geetest_absolute、需要滑動的圖片(c_slice):geetest_canvas_slice geetest_absolute、完整圖片(c_full_bg):geetest_canvas_fullbg geetest_fade geetest_absolute,隨后傳值給 save_screenshot() 函數,進一步對驗證碼進行處理


【13.8】元素可見性設置函數

# 設置元素不可見 def hide_element(element):browser.execute_script("arguments[0].style=arguments[1]", element, "display: none;")# 設置元素可見 def show_element(element):browser.execute_script("arguments[0].style=arguments[1]", element, "display: block;")

【13.9】驗證碼截圖函數

def save_screenshot(obj, name):try:pic_url = browser.save_screenshot('.\\bilibili.png')print("%s:截圖成功!" % pic_url)left = obj.location['x']top = obj.location['y']right = left + obj.size['width']bottom = top + obj.size['height']print('圖:' + name)print('Left %s' % left)print('Top %s' % top)print('Right %s' % right)print('Bottom %s' % bottom)print('')im = Image.open('.\\bilibili.png')im = im.crop((left, top, right, bottom))file_name = 'bili_' + name + '.png'im.save(file_name)except BaseException as msg:print("%s:截圖失敗!" % msg)

location 屬性可以返回該圖片對象在瀏覽器中的位置,坐標軸是以屏幕左上角為原點,x軸向右遞增,y軸向下遞增,size 屬性可以返回該圖片對象的高度和寬度,由此可以得到驗證碼的位置信息,首先調用 save_screenshot() 屬性對整個頁面截圖并保存,然后向 crop() 方法傳入驗證碼的位置信息,由位置信息再對驗證碼進行剪裁并保存


【13.10】滑動函數

def slide():distance = get_distance(Image.open('.\\bili_back.png'), Image.open('.\\bili_full.png'))print('計算偏移量為:%s Px' % distance)trace = get_trace(distance - 5)move_to_gap(trace)time.sleep(3)

向 get_distance() 函數傳入完整的圖片和缺口圖片,計算滑塊需要滑動的距離,再把距離信息傳入 get_trace() 函數,構造滑塊的移動軌跡,最后根據軌跡信息調用 move_to_gap() 函數移動滑塊完成驗證


【13.11】計算滑塊移動距離函數

def get_distance(bg_image, fullbg_image):distance = 60for i in range(distance, fullbg_image.size[0]):for j in range(fullbg_image.size[1]):if not is_pixel_equal(fullbg_image, bg_image, i, j):return i

get_distance() 方法即獲取缺口位置的方法,此方法的參數是兩張圖片,一張為完整的圖片,另一張為帶缺口的圖片,distance 為滑塊的初始位置,遍歷兩張圖片的每個像素,利用 is_pixel_equal() 像素判斷函數判斷兩張圖片同一位置的像素是否相同,比較兩張圖 RGB 的絕對值是否均小于定義的閾值 threshold,如果絕對值均在閾值之內,則代表像素點相同,繼續遍歷,否則代表不相同的像素點,即缺口的位置


【13.12】像素判斷函數

def is_pixel_equal(bg_image, fullbg_image, x, y):bg_pixel = bg_image.load()[x, y]fullbg_pixel = fullbg_image.load()[x, y]threshold = 60if (abs(bg_pixel[0] - fullbg_pixel[0] < threshold) and abs(bg_pixel[1] - fullbg_pixel[1] < threshold) and abs(bg_pixel[2] - fullbg_pixel[2] < threshold)):return Trueelse:return False

將完整圖片和缺口圖片兩個對象分別賦值給變量 bg_image和 fullbg_image,接下來對比圖片獲取缺口。我們在這里遍歷圖片的每個坐標點,獲取兩張圖片對應像素點的 RGB 數據,判斷像素的各個顏色之差,abs() 用于取絕對值,如果二者的 RGB 數據差距在一定范圍內,那就代表兩個像素相同,繼續比對下一個像素點,如果差距超過一定范圍,則代表像素點不同,當前位置即為缺口位置


【13.13】構造移動軌跡函數

def get_trace(distance):trace = []faster_distance = distance * (4 / 5)start, v0, t = 0, 0, 0.1while start < distance:if start < faster_distance:a = 10else:a = -10move = v0 * t + 1 / 2 * a * t * tv = v0 + a * tv0 = vstart += movetrace.append(round(move))return trace

get_trace() 方法傳入的參數為移動的總距離,返回的是運動軌跡,運動軌跡用 trace 表示,它是一個列表,列表的每個元素代表每次移動多少距離,利用 Selenium 進行對滑塊的拖拽時要模仿人的行為,由于有個對準過程,所以是先快后慢,勻速移動、隨機速度移動都不會成功,因此要設置一個加速和減速的距離,這里設置加速距離 faster_distance 是總距離 distance 的4/5倍,滑塊滑動的加速度用 a 來表示,當前速度用 v 表示,初速度用 v0 表示,位移用 move 表示,所需時間用 t 表示,它們之間滿足以下關系:

move = v0 * t + 0.5 * a * t * t v = v0 + a * t

設置初始位置、初始速度、時間間隔分別為0, 0, 0.1,加速階段和減速階段的加速度分別設置為10和-10,直到運動軌跡達到總距離時,循環終止,最后得到的 trace 記錄了每個時間間隔移動了多少位移,這樣滑塊的運動軌跡就得到了


【13.14】模擬拖動函數

def move_to_gap(trace):slider = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.geetest_slider_button')))ActionChains(browser).click_and_hold(slider).perform()for x in trace:ActionChains(browser).move_by_offset(xoffset=x, yoffset=0).perform()time.sleep(0.5)ActionChains(browser).release().perform()

傳入的參數為運動軌跡,首先查找到滑動按鈕,然后調用 ActionChains 的 click_and_hold() 方法按住拖動底部滑塊,perform() 方法用于執行,遍歷運動軌跡獲取每小段位移距離,調用 move_by_offset() 方法移動此位移,最后調用 release() 方法松開鼠標即可


【13.15】效果實現動圖

最終實現效果圖:(關鍵信息已經過打碼處理)


【13.16】完整代碼

from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver import ActionChains import time import random from PIL import Imagedef init():global url, browser, username, password, waiturl = 'https://passport.bilibili.com/login'path = r'F:\PycharmProjects\Python3爬蟲\chromedriver.exe'chrome_options = Options()chrome_options.add_argument('--start-maximized')browser = webdriver.Chrome(executable_path=path, chrome_options=chrome_options)username = '155********'password = '***********'wait = WebDriverWait(browser, 20)def login():browser.get(url)user = wait.until(EC.presence_of_element_located((By.ID, 'login-username')))passwd = wait.until(EC.presence_of_element_located((By.ID, 'login-passwd')))user.send_keys(username)passwd.send_keys(password)login_btn = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'a.btn.btn-login')))time.sleep(random.random() * 3)login_btn.click()def find_element():c_background = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_bg.geetest_absolute')))c_slice = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_slice.geetest_absolute')))c_full_bg = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_fullbg.geetest_fade.geetest_absolute')))hide_element(c_slice)save_screenshot(c_background, 'back')show_element(c_slice)save_screenshot(c_slice, 'slice')show_element(c_full_bg)save_screenshot(c_full_bg, 'full')def hide_element(element):browser.execute_script("arguments[0].style=arguments[1]", element, "display: none;")def show_element(element):browser.execute_script("arguments[0].style=arguments[1]", element, "display: block;")def save_screenshot(obj, name):try:pic_url = browser.save_screenshot('.\\bilibili.png')print("%s:截圖成功!" % pic_url)left = obj.location['x']top = obj.location['y']right = left + obj.size['width']bottom = top + obj.size['height']print('圖:' + name)print('Left %s' % left)print('Top %s' % top)print('Right %s' % right)print('Bottom %s' % bottom)print('')im = Image.open('.\\bilibili.png')im = im.crop((left, top, right, bottom))file_name = 'bili_' + name + '.png'im.save(file_name)except BaseException as msg:print("%s:截圖失敗!" % msg)def slide():distance = get_distance(Image.open('.\\bili_back.png'), Image.open('.\\bili_full.png'))print('計算偏移量為:%s Px' % distance)trace = get_trace(distance - 5)move_to_gap(trace)time.sleep(3)def get_distance(bg_image, fullbg_image):distance = 60for i in range(distance, fullbg_image.size[0]):for j in range(fullbg_image.size[1]):if not is_pixel_equal(fullbg_image, bg_image, i, j):return idef is_pixel_equal(bg_image, fullbg_image, x, y):bg_pixel = bg_image.load()[x, y]fullbg_pixel = fullbg_image.load()[x, y]threshold = 60if (abs(bg_pixel[0] - fullbg_pixel[0] < threshold) and abs(bg_pixel[1] - fullbg_pixel[1] < threshold) and abs(bg_pixel[2] - fullbg_pixel[2] < threshold)):return Trueelse:return Falsedef get_trace(distance):trace = []faster_distance = distance * (4 / 5)start, v0, t = 0, 0, 0.1while start < distance:if start < faster_distance:a = 20else:a = -20move = v0 * t + 1 / 2 * a * t * tv = v0 + a * tv0 = vstart += movetrace.append(round(move))return tracedef move_to_gap(trace):slider = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.geetest_slider_button')))ActionChains(browser).click_and_hold(slider).perform()for x in trace:ActionChains(browser).move_by_offset(xoffset=x, yoffset=0).perform()time.sleep(0.5)ActionChains(browser).release().perform()if __name__ == '__main__':init()login()find_element()slide()

總結

以上是生活随笔為你收集整理的Python3 爬虫学习笔记 C13【验证码对抗系列 — 滑动验证码】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。