使用Python + Selenium破解滑块验证码
在前面一篇博客《使用 Python + Selenium 打造瀏覽器爬蟲》中,我介紹了 Selenium 的基本用法和爬蟲開發(fā)過程中經(jīng)常使用的一些小技巧,利用這些寫出一個(gè)瀏覽器爬蟲已經(jīng)完全沒有問題了。看了前一篇博客,可能有人會(huì)有疑惑,瀏覽器爬蟲的優(yōu)勢(shì)感覺并不比傳統(tǒng)爬蟲多多少啊,特別是通過遍歷頁面元素來獲取爬蟲數(shù)據(jù)的方式和傳統(tǒng)爬蟲解析 HTML 文檔結(jié)構(gòu)的方式如出一轍。為了體現(xiàn)瀏覽器爬蟲的優(yōu)越性,我特意準(zhǔn)備了這篇博客,來看看如果要破解滑塊驗(yàn)證碼,瀏覽器爬蟲比傳統(tǒng)爬蟲要容易多少。
一、滑塊驗(yàn)證碼簡(jiǎn)述
有爬蟲,自然就有反爬蟲,就像病毒和殺毒軟件一樣,有攻就有防,兩者彼此推進(jìn)發(fā)展。反爬技術(shù)歷經(jīng)多年,從最簡(jiǎn)單的檢測(cè) UserAgent 或者 Referrer 等頭部,到限制訪問頻率封 IP 等手段,到關(guān)鍵路徑的行為識(shí)別,到前端頁面的混淆和加密,到目前最流行的驗(yàn)證碼技術(shù),可以說,為了防止網(wǎng)絡(luò)上大量爬蟲的肆意妄為,特別是一些垃圾機(jī)器人,技術(shù)人員真的是絞盡腦汁。但是道高一尺魔高一丈,直到目前為止,也并沒有完全無懈可擊的反爬方案。
目前最流行的反爬技術(shù)是驗(yàn)證碼,幾乎所有網(wǎng)站的注冊(cè)頁面都會(huì)用到驗(yàn)證碼技術(shù),為了防止爬蟲自動(dòng)注冊(cè),批量生成垃圾賬號(hào)。驗(yàn)證碼技術(shù)從一誕生,就是黑客們最感興趣的話題,驗(yàn)證碼的英文為 CAPTCHA(Completely Automated Public Turing test to tell Computers and Humans Apart),翻譯成中文就是 全自動(dòng)區(qū)分計(jì)算機(jī)和人類的公開圖靈測(cè)試,它是一種可以區(qū)分用戶是計(jì)算機(jī)還是人的測(cè)試,只要能通過 CAPTCHA 測(cè)試,該用戶就可以被認(rèn)為是人類。使用計(jì)算機(jī)模擬人類的行為一直以來都是黑客們最熱衷的事情,也是黑客們夢(mèng)寐以求的理想。所以驗(yàn)證碼技術(shù)從一提出,就有大量的人嘗試破解,其實(shí)這些人并不是為了制造垃圾爬蟲,他們只是相信計(jì)算機(jī)可以和人一樣,阿西莫夫的機(jī)器人世界在未來是可能的。
最初的驗(yàn)證碼只是一張圖片,圖片上顯示扭曲變形的文字和數(shù)字,這樣的驗(yàn)證碼通過圖像處理和識(shí)別的技術(shù)可以達(dá)到很高的識(shí)別率。后來驗(yàn)證碼技術(shù)又在圖片上加入了各種干擾項(xiàng),并且將字符粘連在一起,增加了字符切割和識(shí)別的難度,但是很快人們就想出了很多種不同的去噪方法,并使用骨架算法切割粘連字符,還有些人提出使用機(jī)器學(xué)習(xí)算法來切割字符。和圖片驗(yàn)證碼類似的是語音驗(yàn)證碼,不過這種驗(yàn)證碼只是在表現(xiàn)形式上有所區(qū)別,實(shí)質(zhì)上和圖片并沒有太大的變化,采用語音識(shí)別技術(shù)破解也不是難事。而且語音和圖片比起來缺乏交互,花樣要少很多,識(shí)別難度也要低一些,所以只有在給盲人或者對(duì)顏色分辨有障礙的人提供服務(wù)時(shí)才可能會(huì)使用語音驗(yàn)證碼,一般情況下使用的比較少。在靜態(tài)的圖片驗(yàn)證碼被破解之后,又出現(xiàn)了動(dòng)態(tài)的圖片驗(yàn)證碼,將字符動(dòng)態(tài)的顯示在 gif 動(dòng)畫上,不過這也沒什么用,通過圖像識(shí)別技術(shù)一樣可以破解,實(shí)在破解不了的,還可以通過網(wǎng)上一些廉價(jià)的打碼平臺(tái)來人肉識(shí)別。
打碼平臺(tái)的誕生可以說是驗(yàn)證碼領(lǐng)域的一件大事,它雖然不是什么高科技,只是把全世界廉價(jià)的勞動(dòng)力匯集在了一起,就這樣,再復(fù)雜的驗(yàn)證碼都不在話下。這雖然不是什么光榮的事,但是它推動(dòng)了驗(yàn)證碼技術(shù)的發(fā)展,交互式驗(yàn)證碼被開發(fā)出來。傳統(tǒng)的圖片驗(yàn)證碼采用一問一答的形式,只要答案正確,就認(rèn)為驗(yàn)證通過,它并不關(guān)心答案是怎么來的,所以出現(xiàn)了一些人工打碼平臺(tái),你提供一個(gè)問題,它們提供一個(gè)答案,僅此而已。如果不僅僅關(guān)注答案的正確性,還將提交答案的過程記錄下來,通過分析提交答案的過程,完全可以識(shí)別出這是不是一個(gè)人在操作,這就是交互式驗(yàn)證碼的基本思路。這種驗(yàn)證碼很難通過打碼平臺(tái)來破解,因?yàn)槟惚仨殞?duì)著瀏覽器,使用鼠標(biāo)對(duì)驗(yàn)證碼進(jìn)行一系列的交互操作。
最耳熟能詳?shù)慕换ヲ?yàn)證碼莫過于 12306 的了,這種驗(yàn)證碼叫做 圖中點(diǎn)選 式驗(yàn)證碼,同時(shí)提供多個(gè)圖像,讓用戶根據(jù)條件點(diǎn)擊選擇。也有些驗(yàn)證碼是同時(shí)顯示 N 個(gè)變形的漢字讓你選,原理與 12306 的類似,但這種驗(yàn)證碼以其極差的用戶體驗(yàn)遭到很多人的唾棄,這也是大多數(shù)產(chǎn)品不愿意選用的一個(gè)原因。滑塊驗(yàn)證碼 比圖中點(diǎn)選體驗(yàn)好很多,它只需要用戶使用鼠標(biāo)將滑塊從某個(gè)位置拖動(dòng)到另一個(gè)位置即可。程序通過記錄用戶拖動(dòng)滑塊的軌跡,這一串的軌跡數(shù)據(jù)采用模式識(shí)別的手段就可以判斷出這是否是真人在操作。最簡(jiǎn)單的滑塊驗(yàn)證碼是用戶拖動(dòng)滑塊從左拖到右即可,后來又出現(xiàn)了 拼圖式 的滑塊,滑塊作為圖的一部分,然后背景圖中有一個(gè)缺口剛好和滑塊相同形狀,需要用戶將滑塊拖到缺口中拼成一張完整的圖片。現(xiàn)在比較流行的滑塊驗(yàn)證碼有 極驗(yàn) 和 網(wǎng)易云易盾,本篇博客以極驗(yàn)的滑塊驗(yàn)證碼為例,其他的滑塊驗(yàn)證碼原理是類似的。
最新的交互式驗(yàn)證碼甚至只需要用戶點(diǎn)擊一個(gè)按鈕即可驗(yàn)證,不需要做任何其他的操作,譬如 極驗(yàn)的第三代行為驗(yàn)證技術(shù) 和 易盾的智能無感知驗(yàn)證碼。這種驗(yàn)證碼的破解方式和滑塊驗(yàn)證碼不一樣,我目前也沒有太多的了解,后面有時(shí)間再研究研究吧。
最后不得不說的是,還有一種交互式驗(yàn)證碼為短信或電話驗(yàn)證碼,通過將驗(yàn)證碼以短信的形式發(fā)送到你的手機(jī),或者使用語音機(jī)器人自動(dòng)打電話播報(bào)驗(yàn)證碼,更有甚者,需要用戶自己編輯短信將驗(yàn)證碼發(fā)送到某個(gè)號(hào)碼。對(duì)于這種驗(yàn)證碼我認(rèn)為并不能算作是 CAPTCHA,因?yàn)樗玫氖怯脩舻挠邢拶Y源(手機(jī)號(hào))這個(gè)客觀限制,而并非是從技術(shù)角度來區(qū)分人和機(jī)器人的區(qū)別。如果某個(gè)人擁有大量的手機(jī)號(hào)(其實(shí),黑產(chǎn)中確實(shí)也有專門養(yǎng)卡賣卡的),這種驗(yàn)證手段就形同虛設(shè)了。
二、破解思路
目前,極驗(yàn)正在推廣其第三代行為驗(yàn)證技術(shù),滑塊驗(yàn)證碼貌似已經(jīng)沒有前兩年那么流行了,不過仍然有很多網(wǎng)站還在使用滑塊驗(yàn)證碼。譬如我這篇博客就以 春秋航空的會(huì)員注冊(cè)頁面 為例。
好了,上面講了那么多,下面就開始我們的破解之旅吧。
2.1 傳統(tǒng)爬蟲
如果采用傳統(tǒng)爬蟲的方式來破解,首先我們需要測(cè)試下正常驗(yàn)證的情況是什么樣的。在 Chrome 瀏覽器中按 F12 打開開發(fā)者工具,然后拖動(dòng)滑塊到正確位置,可以觀察到 Network 面板發(fā)送的 Ajax 請(qǐng)求。
可以看到這個(gè)請(qǐng)求的參數(shù)非常復(fù)雜,每個(gè)參數(shù)的含義也完全沒有頭緒,如果要破解這個(gè)驗(yàn)證碼,則必須模擬發(fā)送這個(gè)請(qǐng)求,這個(gè)請(qǐng)求的每個(gè)參數(shù)都必須弄清楚,于是我們?cè)诖a中搜索發(fā)送這個(gè)請(qǐng)求的地方。但事實(shí)上到這里我們就遇到了困難,ajax.php 這個(gè)請(qǐng)求根本就搜不到,甚至在瀏覽器中下 XHR 斷點(diǎn)也不行(很顯然它并不是一個(gè) Ajax 請(qǐng)求),這是因?yàn)闃O驗(yàn)的核心代碼經(jīng)過了代碼混淆。
這樣的代碼也就只有機(jī)器能讀懂,大多數(shù)人肯定是直接放棄了。不過網(wǎng)上也有大量的分析文章,如果你感興趣可以自己研究下,譬如 Windows應(yīng)用開發(fā) 的知乎專欄上就有幾篇介紹 極驗(yàn)驗(yàn)證碼破解的系列文章,還有 FanhuaandLuomu 的 這篇破解文章 也寫得很好,推薦。
我在這里跳過對(duì)混淆代碼的分析,總結(jié)下破解這樣的滑塊驗(yàn)證碼的思路:
1、捕獲所有關(guān)鍵請(qǐng)求;
2、分析調(diào)試混淆的代碼,弄懂每個(gè)請(qǐng)求每個(gè)參數(shù)的含義,其中肯定會(huì)有一個(gè)參數(shù),是拖動(dòng)滑塊的軌跡;
3、驗(yàn)證碼圖片是打亂的,需要解析頁面上的樣式,并使用圖像處理方法還原出原始圖像;
4、根據(jù)原始的圖像和滑塊位置得到缺口的偏移量;
5、滑塊軌跡的模擬;
6、如果參數(shù)有加密處理,還需要模擬它的加密過程;實(shí)在不行可以直接在代碼里模擬執(zhí)行頁面上的 JS;
7、...
可見這里的工作量非常大,破解難度可想而知,而且混淆的代碼隨時(shí)可能會(huì)發(fā)布新的版本,一旦版本升級(jí),參數(shù)都有可能發(fā)生變化,之前的所有分析工作都可能前功盡棄。
除非實(shí)在是迫不得已,我并不推薦傳統(tǒng)的這種破解方法。首先這樣的破解方法太脆弱,不夠通用,隨時(shí)可能失效;其次這樣的破解工作費(fèi)時(shí)費(fèi)力,就算破解出來也得不到成就感和滿足感,對(duì)程序員的打擊太大,他可能再也不會(huì)玩第二次了(除非他是極客中的極客,就以破解混淆代碼為樂)。所以,還是讓我們來看看瀏覽器爬蟲如何。
2.2 瀏覽器爬蟲
由于瀏覽器爬蟲完全是以人為第一視角,你所看到的,就是瀏覽器爬蟲看到的,甚至,它能比你看到更多。我們可以大概的總結(jié)下瀏覽器爬蟲的破解思路:
圖像識(shí)別,找到滑塊的位置和缺口的位置;
模擬鼠標(biāo)拖動(dòng),將滑塊拖到缺口位置;
沒錯(cuò),就兩步。雖然其中會(huì)遇到一些坑,但真的就這兩步。使用上一篇博客中介紹的 Selenium 技巧,可以很快的寫下下面的代碼:
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--start-maximized")
browser = webdriver.Chrome(
executable_path="./drivers/chromedriver.exe",
chrome_options=chrome_options
)
browser.get('https://account.ch.com/NonRegistrations-Regist')
Wait(browser, 60).until(
Expect.visibility_of_element_located((By.CSS_SELECTOR, "div[data-target='account-login']"))
)
email = browser.find_element_by_css_selector("div[data-target='account-login']")
email.click()
Wait(browser, 60).until(
Expect.visibility_of_element_located((By.ID, "emailRegist"))
)
register = browser.find_element_by_id("emailRegist")
register.click()
offset = get_gap_offset(browser)
drag_and_drop(browser, offset)
關(guān)鍵就在于最后兩個(gè)方法 get_gap_offset() 和 drag_and_drop(),下面就來看下這兩個(gè)方法的實(shí)現(xiàn)。
三、驗(yàn)證碼圖片處理
審查驗(yàn)證碼圖片元素,可以看到下面這樣的 HTML 代碼:
<div class="gt_cut_fullbg_slice"></div>
這樣的代碼一共有 52 行,每一個(gè) div 都是 10px * 58px 的小塊。我們打開這個(gè) background-image 對(duì)應(yīng)的圖片可以看出這是一張亂序的圖片,這里的 background-position 用于顯示出正確的圖片。在代碼上面,可以發(fā)現(xiàn)和這里完全類似的代碼,background-position 都完全一樣,只是 background-image 不一樣,我們打開對(duì)應(yīng)的圖片,也是亂序的,但和上一張圖片對(duì)比,可以猜測(cè)出,這是帶有缺口的背景圖片。
<div class="gt_cut_bg_slice"></div>
一個(gè)很自然的想法就是把這兩張亂序的圖片根據(jù) background-position 重組成兩張看得懂的圖片,然后對(duì)比兩張圖片,得到缺口的偏移量,然后將缺口偏移量減去滑塊偏移量,就可以得到要拖動(dòng)的偏移量。如下圖所示:
其中滑塊的偏移量可以通過下面的代碼得到(其中,left: 12px 就是滑塊的偏移量):
<div class="gt_slice gt_show"></div>
這里需要用到一點(diǎn)點(diǎn)圖像處理的知識(shí),我們采用大名鼎鼎的 Pillow,Pillow 是 Python 里的圖像處理庫(PIL:Python Image Library),在開始之前,可以先看下它的官網(wǎng)教程,這里有一份中文文檔也可以參考。計(jì)算缺口偏移量的關(guān)鍵代碼如下:
def get_slider_offset(image_url, image_url_bg, css):
image_file = io.BytesIO(requests.get(image_url).content)
im = Image.open(image_file)
image_file_bg = io.BytesIO(requests.get(image_url_bg).content)
im_bg = Image.open(image_file_bg)
# 10*58 26/row => background image size = 260*116
captcha = Image.new('RGB', (260, 116))
captcha_bg = Image.new('RGB', (260, 116))
for i, px in enumerate(css):
offset = convert_css_to_offset(px)
region = im.crop(offset)
region_bg = im_bg.crop(offset)
offset = convert_index_to_offset(i)
captcha.paste(region, offset)
captcha_bg.paste(region_bg, offset)
diff = ImageChops.difference(captcha, captcha_bg)
return get_slider_offset_from_diff_image(diff)
代碼很好理解,就是根據(jù) css 將兩張背景圖片重新排序生成兩張新圖片,然后通過 ImageChops.difference() 方法得到兩張圖片的差值圖像,最后通過差值圖像得到缺口的偏移量。其中有一點(diǎn)要注意的是,Pillow 的 Image.open() 方法只支持文件,不支持 URL,所以將圖片轉(zhuǎn)換為 BytesIO 對(duì)象,BytesIO 和 StringIO 一樣,是 Python 提供的在內(nèi)存中操作 bytes 和 str 的類,并且和讀寫文件具有一致的接口。
這種計(jì)算缺口位置的方法需要解析頁面源碼以及圖片的 CSS 樣式,其實(shí)還有一種更簡(jiǎn)單的方法:在顯示驗(yàn)證碼圖片時(shí)對(duì)瀏覽器進(jìn)行截圖,這個(gè)時(shí)候的圖像是完整的背景圖像;然后再點(diǎn)擊滑塊,這個(gè)時(shí)候滑塊和缺口都會(huì)顯示出來,再對(duì)瀏覽器進(jìn)行截圖;分析兩次的截圖也可以計(jì)算出拖動(dòng)的偏移量。有興趣的同學(xué)可以一試。
......
總結(jié)
以上是生活随笔為你收集整理的使用Python + Selenium破解滑块验证码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 教你二级路由器怎么设置更换二级路由器如何
- 下一篇: 怎么给文件夹加密如何给电脑文件夹加密