selenium+opencv實(shí)現(xiàn)滑塊驗(yàn)證碼的登陸
很多網(wǎng)站登錄登陸時(shí)都要用到滑塊驗(yàn)證碼,在某些場(chǎng)景例如使用爬蟲爬取信息時(shí)常常受到阻礙,想著用opencv的模板匹配試試能不能實(shí)現(xiàn)模擬登陸。本來覺得網(wǎng)上資料多應(yīng)該還蠻容易,但實(shí)際上手還是搞了蠻久,在這里記錄一下整個(gè)流程,網(wǎng)站無所謂主要是要有滑動(dòng)驗(yàn)證碼:
環(huán)境
python 3.9, selenium和Opencv相關(guān)依賴,用于抓取圖片的requests包,具體安裝這里不多講了,其中selenium用的火狐版本。
selenium登錄網(wǎng)站
整體流程就是這個(gè)樣子:訪問網(wǎng)站->點(diǎn)擊登錄->輸入賬號(hào)密碼->搞定滑塊驗(yàn)證->登錄網(wǎng)站,其中最大的難點(diǎn)是滑塊驗(yàn)證碼,但在此之前我們當(dāng)然要先讓selenium自動(dòng)打開網(wǎng)站把賬號(hào)密碼輸好,我們通過find_element()方法定位輸入框之后執(zhí)行操作,元素的各個(gè)屬性F12就可以找到:
代碼如下:
options = webdriver.FirefoxOptions() driver = webdriver.Firefox(options=options) driver.get('網(wǎng)址') driver.find_element("link text", "登錄").click() name = driver.find_element("id", "name-input") name.send_keys("賬號(hào)######") # 輸入賬號(hào) pw = driver.find_element("id", "password-input") pw.send_keys("密碼#########") # 輸入密碼 driver.find_element("id", "submit").click() # 提交
requests抓取驗(yàn)證碼圖片
為了做后續(xù)處理我們需要把滑塊驗(yàn)證碼相關(guān)圖片抓到本地,網(wǎng)上關(guān)于滑塊驗(yàn)證碼這塊很多都是用原圖和有缺口的圖對(duì)比來確定缺口位置的,但是我并沒有找到原圖,這里用到的是有缺口的背景圖和滑塊圖,如下:
滑塊圖:
有缺口的背景圖:
這里爬圖是selenium定位之后用requests包爬的,注意驗(yàn)證碼和登陸界面不在一個(gè)iframe里,selenium記得切到對(duì)應(yīng)iframe才能定位到圖片,代碼如下:
driver.switch_to.frame('tcaptcha_iframe') # 切換iframe img = driver.find_element("id", "slideBg").get_attribute('src') headers = { 'Accept': "application/json, text/plain, */*", 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" } # 請(qǐng)求頭 r = requests.get(img, headers=headers) with open('img.png', 'wb') as f: f.write(r.content) block = driver.find_element("id", "slideBlock").get_attribute('src') r = requests.get(block, headers=headers) with open('block.png', 'wb') as f: f.write(r.content)
OpenCV識(shí)別缺口位置
接下來就是重點(diǎn),如何確定缺口位置來定位滑動(dòng)驗(yàn)證碼該往哪滑。這里主要用到OpenCV的模板匹配。 首先對(duì)滑塊也就是稍后匹配時(shí)用到的模板進(jìn)行處理,這里主要就是把形狀輪廓提取出來然后去掉多余的東西,先把原圖變成灰度圖:
tpl_gray = cv2.cvtColor(tpl, cv2.COLOR_BGR2GRAY)
可以看到邊緣有一圈陰影部分,我們需要把周圍這圈去掉,遍歷找到黑色像素點(diǎn)把它變成和周圍一樣。
width, height = tpl_gray.shape for h in range(height): for w in range(width): if tpl_gray[w, h] == 0: tpl_gray[w, h] = 96
處理后變成了這樣,然后把中間主體部分涂黑,也就是將圖片二值化。
binary = cv2.inRange(tpl_gray, 96, 96) # 二值化 kernel = np.ones((8, 8), np.uint8) template = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel) # 去白色噪點(diǎn)
處理完畢得到理想的模板圖:
接下來對(duì)帶有缺口的背景圖進(jìn)行處理,這個(gè)過程稍微麻煩一點(diǎn),不過思路還是比較清晰的,還是先轉(zhuǎn)化成灰度圖再二值化,這里有一個(gè)問題,不同驗(yàn)證碼圖片之間差距很大,有的顏色很顯眼,有的卻很清淡,比如下面這兩差別太大了,這就導(dǎo)致在二值化的過程中很難有一個(gè)固定的參數(shù)。
這里我根據(jù)圖片的平均灰度值設(shè)定了幾個(gè)區(qū)間,對(duì)不同區(qū)間的驗(yàn)證碼圖片傳入不同參數(shù)進(jìn)行二值化:
def avg_mean(img): mean_val, _, _, _ = cv2.mean(img) print("平均灰度:", mean_val) return mean_val def match(img): gauss = cv2.GaussianBlur(img, [5, 5], 0) img_gray = cv2.cvtColor(gauss, cv2.COLOR_BGR2GRAY) cv2.imshow("111", img_gray) if avg_mean(img) > 140: # 二值化 ret, target = cv2.threshold(img_gray, 105, 255, cv2.THRESH_BINARY) elif avg_mean(img) > 102: ret, target = cv2.threshold(img_gray, 95, 255, cv2.THRESH_BINARY) else: ret, target = cv2.threshold(img_gray, 85, 255, cv2.THRESH_BINARY)
處理過的結(jié)果大概像這樣:
效果還是不錯(cuò)的,清晰的凸顯了缺口位置,最后把背景圖和模板傳入opencv的模板匹配方法,記錄下匹配到的坐標(biāo)即可。
result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) left_up = max_loc print(left_up) right_down = (left_up[0] + height, left_up[1] + width) cv2.rectangle(img, left_up, right_down, (0, 0, 255), 2) cv2.imshow('res', img)
這里框出來看看效果:
模擬拖動(dòng)滑塊
識(shí)別出位置之后就要算出滑塊移動(dòng)了多少距離,我們可以看到滑塊初始狀態(tài)距離邊緣有26個(gè)像素:
同時(shí)抓下來的圖片相比在網(wǎng)頁中放大了一倍,所以真實(shí)滑動(dòng)距離是:
(left_up - 26*2)/2
于是用selenium的actionchains模擬拖動(dòng)滑塊:
def drag_block(l): drag = driver.find_element("id", "tcaptcha_drag_button") ActionChains(driver).click_and_hold(on_element=drag).perform() ActionChains(driver).move_to_element_with_offset(to_element=drag, xoffset=l, yoffset=0).perform() ActionChains(driver).release().perform()
這樣整個(gè)流程就搞定了,理論上這樣簡單粗暴的自動(dòng)拖過去在很多時(shí)候會(huì)不奏效,還需要模擬人手動(dòng)拖動(dòng),不過因?yàn)槲易鰷y(cè)試的時(shí)候直接就成功了,所以沒寫下去,整體思路大概是加速減速停幾秒或者中間觸發(fā)幾個(gè)mouse_up(),mouse_down()事件。
腳本示例:
下面是測(cè)試時(shí)用到的腳本,selenium部分和主函數(shù),拿某個(gè)CTF靶場(chǎng)做的測(cè)試,僅供參考,根據(jù)實(shí)際網(wǎng)站不同肯定得改改:
import time import requests from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains import block_loc def drag_block(l): drag = driver.find_element("id", "tcaptcha_drag_button") ActionChains(driver).click_and_hold(on_element=drag).perform() ActionChains(driver).move_to_element_with_offset(to_element=drag, xoffset=l, yoffset=0).perform() ActionChains(driver).release().perform() def login_in(username, password): headers = { 'Accept': "application/json, text/plain, */*", 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" } driver.get('網(wǎng)址') driver.find_element("link text", "登錄").click() name = driver.find_element("id", "name-input") name.send_keys(username) pw = driver.find_element("id", "password-input") pw.send_keys(password) driver.find_element("id", "submit").click() time.sleep(2) driver.switch_to.frame('tcaptcha_iframe') img = driver.find_element("id", "slideBg").get_attribute('src') r = requests.get(img, headers=headers) with open('img.png', 'wb') as f: f.write(r.content) block = driver.find_element("id", "slideBlock").get_attribute('src') r = requests.get(block, headers=headers) with open('block.png', 'wb') as f: f.write(r.content) if __name__ == '__main__': options = webdriver.FirefoxOptions() driver = webdriver.Firefox(options=options) user = "##########" pw = "############" login_in(user, pw) image = "img.png" tpl = "block.png" length = block_loc.match(image, tpl) print(length) drag_block(length)
Opencv部分:
import cv2 import numpy as np def avg_mean(img): mean_val, _, _, _ = cv2.mean(img) print("平均灰度:", mean_val) return mean_val def match(image, temp): img = cv2.imread(image) tpl = cv2.imread(temp) tpl_gray = cv2.cvtColor(tpl, cv2.COLOR_BGR2GRAY) # cv2.imshow("111", tpl_gray) width, height = tpl_gray.shape for h in range(height): for w in range(width): if tpl_gray[w, h] == 0: tpl_gray[w, h] = 96 binary = cv2.inRange(tpl_gray, 96, 96) kernel = np.ones((8, 8), np.uint8) template = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel) # cv2.imshow('tpl', template) print(img.shape) gauss = cv2.GaussianBlur(img, [5, 5], 0) img_gray = cv2.cvtColor(gauss, cv2.COLOR_BGR2GRAY) # cv2.imshow("111", img_gray) if avg_mean(img) > 140: ret, target = cv2.threshold(img_gray, 105, 255, cv2.THRESH_BINARY) # 二值化 elif avg_mean(img) > 102: ret, target = cv2.threshold(img_gray, 95, 255, cv2.THRESH_BINARY) # 二值化 else: ret, target = cv2.threshold(img_gray, 80, 255, cv2.THRESH_BINARY) # cv2.imshow('target', target) result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) left_up = max_loc print(left_up) right_down = (left_up[0] + height, left_up[1] + width) cv2.rectangle(img, left_up, right_down, (0, 0, 255), 2) # cv2.imshow('res', img) length = (left_up[0] - 26*2)/2 return length
到此這篇關(guān)于selenium+opencv實(shí)現(xiàn)滑塊驗(yàn)證碼的登陸的文章就介紹到這了,更多相關(guān)selenium opencv 滑塊驗(yàn)證碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python實(shí)現(xiàn)從字典中刪除元素的方法
這篇文章主要介紹了python實(shí)現(xiàn)從字典中刪除元素的方法,涉及Python中del方法的使用技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-05-05python使用turtle庫繪制奧運(yùn)五環(huán)
turtle也叫海龜,是turtle繪圖體系的python實(shí)現(xiàn),這篇文章主要介紹了python使用turtle庫繪制奧運(yùn)五環(huán),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2020-02-02給keras層命名,并提取中間層輸出值,保存到文檔的實(shí)例
這篇文章主要介紹了給keras層命名,并提取中間層輸出值,保存到文檔的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-05-05有關(guān)wxpython pyqt內(nèi)存占用問題分析
一直覺得wxpython占用內(nèi)存比較多,在工作中寫的一些小程序應(yīng)用,一對(duì)比其它的小程序,發(fā)現(xiàn)內(nèi)存相差確實(shí)有點(diǎn)大2014-06-06python區(qū)塊鏈創(chuàng)建多個(gè)交易教程
這篇文章主要為大家介紹了python區(qū)塊鏈創(chuàng)建多個(gè)交易的實(shí)現(xiàn)示例教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05Python 中使用 argparse 解析命令行參數(shù)
這篇文章主要介紹了Python 中使用 argparse 解析命令行參數(shù),argparse 模塊是一個(gè)強(qiáng)大的命令行參數(shù)解析器,還有很多功能沒能在這里介紹。下面文化在哪個(gè)詳細(xì)介紹該內(nèi)容,需要的朋友可以參考一下2021-11-11