Python3爬蟲(chóng)關(guān)于識(shí)別點(diǎn)觸點(diǎn)選驗(yàn)證碼的實(shí)例講解
上一節(jié)我們實(shí)現(xiàn)了極驗(yàn)驗(yàn)證碼的識(shí)別,但是除了極驗(yàn)其實(shí)還有另一種常見(jiàn)的且應(yīng)用廣泛的驗(yàn)證碼,比較有代表性的就是點(diǎn)觸驗(yàn)證碼。
可能你對(duì)這個(gè)名字比較陌生,但是肯定見(jiàn)過(guò)類似的驗(yàn)證碼,比如 12306,這就是一種典型的點(diǎn)觸驗(yàn)證碼,如圖所示:
我們需要直接點(diǎn)擊圖中符合要求的圖,如果所有答案均正確才會(huì)驗(yàn)證成功,如果有一個(gè)答案錯(cuò)誤,驗(yàn)證就會(huì)失敗,這種驗(yàn)證碼就可以稱之為點(diǎn)觸驗(yàn)證碼。
另外還有一個(gè)專門提供點(diǎn)觸驗(yàn)證碼服務(wù)的站點(diǎn),叫做 TouClick,其官方網(wǎng)站為:https://www.touclick.com/,本節(jié)就以它為例講解一下此類驗(yàn)證碼的識(shí)別過(guò)程。
1. 本節(jié)目標(biāo)
本節(jié)我們的目標(biāo)是用程序來(lái)識(shí)別并通過(guò)點(diǎn)觸驗(yàn)證碼的驗(yàn)證。
2. 準(zhǔn)備工作
本次我們使用的 Python 庫(kù)是 Selenium,使用的瀏覽器為 Chrome,在此之前請(qǐng)確保已經(jīng)正確安裝好了 Selenium 庫(kù)、Chrome瀏覽器并配置好了 ChromeDriver,相關(guān)流程可以參考第一章的說(shuō)明。
3. 了解點(diǎn)觸驗(yàn)證碼
TouClick 官方網(wǎng)站的驗(yàn)證碼樣式如圖 8-19 所示:
和 12306 站點(diǎn)有相似之處,不過(guò)這次是點(diǎn)擊圖片中的文字,不是圖片了,另外還有各種形形色色的點(diǎn)觸驗(yàn)證碼,其交互形式可能略有不同,但基本原理都是類似的。
接下來(lái)我們就來(lái)統(tǒng)一實(shí)現(xiàn)一下此類點(diǎn)觸驗(yàn)證碼的識(shí)別過(guò)程。
4. 識(shí)別思路
此種驗(yàn)證碼的如果依靠圖像識(shí)別的話識(shí)別難度非常之大。
例如就 12306 來(lái)說(shuō),其識(shí)別難點(diǎn)有兩個(gè)點(diǎn),第一點(diǎn)是文字識(shí)別,如圖 8-20 所示:
如點(diǎn)擊圖中所有的漏斗,“漏斗”二字其實(shí)都經(jīng)過(guò)變形、放縮、模糊處理了,如果要借助于前面我們講的 OCR 技術(shù)來(lái)識(shí)別,識(shí)別的精準(zhǔn)度會(huì)大打折扣,甚至得不到任何結(jié)果。第二點(diǎn)是圖像的識(shí)別,我們需要將圖像重新轉(zhuǎn)化文字,可以借助于各種識(shí)圖接口,可經(jīng)我測(cè)試識(shí)別正確結(jié)果的準(zhǔn)確率非常低,經(jīng)常會(huì)出現(xiàn)匹配不正確或匹配不出結(jié)果的情況,而且圖片本身的的清晰度也不夠,所以識(shí)別難度會(huì)更大,更何況需要同時(shí)識(shí)別出八張圖片的結(jié)果,且其中幾個(gè)答案需要完全匹配正確才能驗(yàn)證通過(guò),綜合來(lái)看,此種方法基本是不可行的。
再拿 TouClick 來(lái)說(shuō),如圖所示:
我們需要從這幅圖片中識(shí)別出植株二字,但是圖片的背景或多或少會(huì)有干擾,導(dǎo)致 OCR 幾乎不會(huì)識(shí)別出結(jié)果,有人會(huì)說(shuō),直接識(shí)別白色的文字不就好了嗎?但是如果換一張驗(yàn)證碼呢?如圖 8-22 所示:
這張驗(yàn)證碼圖片的文字又變成了藍(lán)色,而且還又有白色陰影,識(shí)別的難度又會(huì)大大增加。
那么此類驗(yàn)證碼就沒(méi)法解了嗎?答案當(dāng)然是有,靠什么?靠人。
靠人解決?那還要程序做什么?不要急,這里說(shuō)的人并不是我們自己去解,在互聯(lián)網(wǎng)上存在非常多的驗(yàn)證碼服務(wù)平臺(tái),平臺(tái) 7×24 小時(shí)提供驗(yàn)證碼識(shí)別服務(wù),一張圖片幾秒就會(huì)獲得識(shí)別結(jié)果,準(zhǔn)確率可達(dá) 90% 以上,但是就需要花點(diǎn)錢來(lái)購(gòu)買服務(wù)了,畢竟平臺(tái)都是需要盈利的,不過(guò)不用擔(dān)心,識(shí)別一個(gè)驗(yàn)證碼只需要幾分錢。
在這里我個(gè)人比較推薦的一個(gè)平臺(tái)是超級(jí)鷹。
其提供的服務(wù)種類非常廣泛,可識(shí)別的驗(yàn)證碼類型非常多,其中就包括此類點(diǎn)觸驗(yàn)證碼。
另外超級(jí)鷹平臺(tái)同樣支持簡(jiǎn)單的圖形驗(yàn)證碼識(shí)別,如果 OCR 識(shí)別有難度,同樣可以用本節(jié)相同的方法借助此平臺(tái)來(lái)識(shí)別,下面是此平臺(tái)提供的一些服務(wù):
英文數(shù)字,提供最多20位英文數(shù)字的混合識(shí)別
中文漢字,提供最多7個(gè)漢字的識(shí)別
純英文,提供最多12位的英文的識(shí)別
純數(shù)字,提供最多11位的數(shù)字的識(shí)別
任意特殊字符,提供不定長(zhǎng)漢字英文數(shù)字、拼音首字母、計(jì)算題、成語(yǔ)混合、 集裝箱號(hào)等字符的識(shí)別
坐標(biāo)選擇識(shí)別,如復(fù)雜計(jì)算題、選擇題四選一、問(wèn)答題、點(diǎn)擊相同的字、物品、動(dòng)物等返回多個(gè)坐標(biāo)的識(shí)別
而本節(jié)我們需要解決的就是屬于最后一類,坐標(biāo)多選識(shí)別的情況,我們需要做的就是將驗(yàn)證碼圖片提交給平臺(tái),然后平臺(tái)會(huì)返回識(shí)別結(jié)果在圖片中的坐標(biāo)位置,接下來(lái)我們?cè)俳馕鲎鴺?biāo)模擬點(diǎn)擊就好了。
原理非常簡(jiǎn)單,下面我們就來(lái)實(shí)際用程序來(lái)實(shí)驗(yàn)一下。
5. 注冊(cè)賬號(hào)
在開(kāi)始之前,我們需要先注冊(cè)一個(gè)超級(jí)鷹賬號(hào)并申請(qǐng)一個(gè)軟件ID,注冊(cè)頁(yè)面鏈接為:https://www.chaojiying.com/user/reg/,注冊(cè)完成之后還需要在后臺(tái)開(kāi)發(fā)商中心添加一個(gè)軟件ID,最后一件事就是充值一些題分,充值多少可以根據(jù)價(jià)格和識(shí)別量自行決定。
6. 獲取API
做好上面的準(zhǔn)備工作之后我們就可以開(kāi)始用程序來(lái)對(duì)接驗(yàn)證碼的識(shí)別了。
首先我們可以到官方網(wǎng)站下載對(duì)應(yīng)的 Python API,鏈接為:https://www.chaojiying.com/api-14.html,但是此 API 是Python2 版本的,是用 Requests 庫(kù)來(lái)實(shí)現(xiàn)的,我們可以簡(jiǎn)單更改幾個(gè)地方即可將其修改為 Python3 版本。
修改之后的API如下:
import requests from hashlib import md5 class Chaojiying(object): def __init__(self, username, password, soft_id): self.username = username self.password = md5(password.encode('utf-8')).hexdigest() self.soft_id = soft_id self.base_params = { 'user': self.username, 'pass2': self.password, 'softid': self.soft_id, } self.headers = { 'Connection': 'Keep-Alive', 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)', } def post_pic(self, im, codetype): """ im: 圖片字節(jié) codetype: 題目類型 參考 http://www.chaojiying.com/price.html """ params = { 'codetype': codetype, } params.update(self.base_params) files = {'userfile': ('ccc.jpg', im)} r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers) return r.json() def report_error(self, im_id): """ im_id:報(bào)錯(cuò)題目的圖片ID """ params = { 'id': im_id, } params.update(self.base_params) r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers) return r.json()
這里定義了一個(gè) Chaojiying 類,其構(gòu)造函數(shù)接收三個(gè)參數(shù),分別是超級(jí)鷹的用戶名、密碼以及軟件ID,保存好以備使用。
接下來(lái)是最重要的一個(gè)方法叫做 post_pic(),這里需要傳入圖片對(duì)象和驗(yàn)證碼的代號(hào),該方法會(huì)將圖片對(duì)象和相關(guān)信息發(fā)給超級(jí)鷹的后臺(tái)進(jìn)行識(shí)別,然后將識(shí)別成功的 Json 返回回來(lái)。
另一個(gè)方法叫做 report_error(),這個(gè)是發(fā)生錯(cuò)誤的時(shí)候的回調(diào),如果驗(yàn)證碼識(shí)別錯(cuò)誤,調(diào)用此方法會(huì)返還相應(yīng)的題分。
接下來(lái)我們以 TouClick 的官網(wǎng)為例來(lái)進(jìn)行演示點(diǎn)觸驗(yàn)證碼的識(shí)別過(guò)程,鏈接為:http://admin.touclick.com/,如果沒(méi)有注冊(cè)賬號(hào)可以先注冊(cè)一個(gè)。
7. 初始化
首先我們需要初始化一些變量,如 WebDriver、Chaojiying對(duì)象等等,代碼實(shí)現(xiàn)如下:
EMAIL = 'cqc@cuiqingcai.com' PASSWORD = '' # 超級(jí)鷹用戶名、密碼、軟件ID、驗(yàn)證碼類型 CHAOJIYING_USERNAME = 'Germey' CHAOJIYING_PASSWORD = '' CHAOJIYING_SOFT_ID = 893590 CHAOJIYING_KIND = 9102 class CrackTouClick(): def __init__(self): self.url = 'http://admin.touclick.com/login.html' self.browser = webdriver.Chrome() self.wait = WebDriverWait(self.browser, 20) self.email = EMAIL self.password = PASSWORD self.chaojiying = Chaojiying(CHAOJIYING_USERNAME, CHAOJIYING_PASSWORD, CHAOJIYING_SOFT_ID)
這里的賬號(hào)和密碼請(qǐng)自行修改。
8. 獲取驗(yàn)證碼
接下來(lái)的第一步就是完善相關(guān)表單,然后模擬點(diǎn)擊呼出驗(yàn)證碼,此步非常簡(jiǎn)單,代碼實(shí)現(xiàn)如下:
def open(self): """ 打開(kāi)網(wǎng)頁(yè)輸入用戶名密碼 :return: None """ self.browser.get(self.url) email = self.wait.until(EC.presence_of_element_located((By.ID, 'email'))) password = self.wait.until(EC.presence_of_element_located((By.ID, 'password'))) email.send_keys(self.email) password.send_keys(self.password) def get_touclick_button(self): """ 獲取初始驗(yàn)證按鈕 :return: """ button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'touclick-hod-wrap'))) return button
在這里 open() 方法負(fù)責(zé)填寫(xiě)表單,get_touclick_button() 方法則是獲取驗(yàn)證碼按鈕,隨后觸發(fā)點(diǎn)擊即可。
接下來(lái)我們需要類似上一節(jié)極驗(yàn)驗(yàn)證碼圖像獲取一樣,首先獲取驗(yàn)證碼圖片的位置和大小,隨后從網(wǎng)頁(yè)截圖里面截取相應(yīng)的驗(yàn)證碼圖片就好了。代碼實(shí)現(xiàn)如下:
def get_touclick_element(self): """ 獲取驗(yàn)證圖片對(duì)象 :return: 圖片對(duì)象 """ element = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'touclick-pub-content'))) return element def get_position(self): """ 獲取驗(yàn)證碼位置 :return: 驗(yàn)證碼位置元組 """ element = self.get_touclick_element() time.sleep(2) location = element.location size = element.size top, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size[ 'width'] return (top, bottom, left, right) def get_screenshot(self): """ 獲取網(wǎng)頁(yè)截圖 :return: 截圖對(duì)象 """ screenshot = self.browser.get_screenshot_as_png() screenshot = Image.open(BytesIO(screenshot)) return screenshot def get_touclick_image(self, name='captcha.png'): """ 獲取驗(yàn)證碼圖片 :return: 圖片對(duì)象 """ top, bottom, left, right = self.get_position() print('驗(yàn)證碼位置', top, bottom, left, right) screenshot = self.get_screenshot() captcha = screenshot.crop((left, top, right, bottom)) return captcha
在這里 get_touclick_image() 方法即為從網(wǎng)頁(yè)截圖中截取對(duì)應(yīng)的驗(yàn)證碼圖片,其中驗(yàn)證碼圖片的相對(duì)位置坐標(biāo)由 get_position() 方法返回得到,最后我們得到的是一個(gè) Image 對(duì)象。
9. 識(shí)別驗(yàn)證碼
隨后我們調(diào)用 Chaojiying 對(duì)象的 post_pic() 方法即可把圖片發(fā)送給超級(jí)鷹后臺(tái),在這里發(fā)送的圖像是字節(jié)流格式,代碼實(shí)現(xiàn)如下:
image = self.get_touclick_image() bytes_array = BytesIO() image.save(bytes_array, format='PNG') # 識(shí)別驗(yàn)證碼 result = self.chaojiying.post_pic(bytes_array.getvalue(), CHAOJIYING_KIND) print(result)
這樣運(yùn)行之后 result 變量就是超級(jí)鷹后臺(tái)的識(shí)別結(jié)果,可能運(yùn)行需要等待幾秒,畢竟后臺(tái)還有人工來(lái)完成識(shí)別。
返回的結(jié)果是一個(gè) Json,如果識(shí)別成功后一個(gè)典型的返回結(jié)果類似如下:
{'err_no': 0, 'err_str': 'OK', 'pic_id': '6002001380949200001', 'pic_str': '132,127|56,77', 'md5': '1f8e1d4bef8b 11484cb1f1f34299865b'}
其中 pic_str 就是識(shí)別的文字的坐標(biāo),是以字符串形式返回的,每個(gè)坐標(biāo)都以 | 分隔,所以接下來(lái)我們只需要將其解析之后再模擬點(diǎn)擊即可,代碼實(shí)現(xiàn)如下:
def get_points(self, captcha_result): """ 解析識(shí)別結(jié)果 :param captcha_result: 識(shí)別結(jié)果 :return: 轉(zhuǎn)化后的結(jié)果 """ groups = captcha_result.get('pic_str').split('|') locations = [[int(number) for number in group.split(',')] for group in groups] return locations def touch_click_words(self, locations): """ 點(diǎn)擊驗(yàn)證圖片 :param locations: 點(diǎn)擊位置 :return: None """ for location in locations: print(location) ActionChains(self.browser).move_to_element_with_offset(self.get_touclick_element(), location[0], location[1]).click().perform() time.sleep(1)
在這里我們用 get_points() 方法將識(shí)別結(jié)果變成了列表的形式,最后 touch_click_words() 方法則通過(guò)調(diào)用 move_to_element_with_offset() 方法依次傳入解析后的坐標(biāo),然后點(diǎn)擊即可。
這樣我們就可以模擬完成坐標(biāo)的點(diǎn)選了,運(yùn)行效果如圖所示:
最后我們需要做的就是點(diǎn)擊提交驗(yàn)證的按鈕等待驗(yàn)證通過(guò),再點(diǎn)擊登錄按鈕即可成功登錄,后續(xù)實(shí)現(xiàn)在此不再贅述。
這樣我們就借助于在線驗(yàn)證碼平臺(tái)完成了點(diǎn)觸驗(yàn)證碼的識(shí)別,此種方法也是一種通用方法,用此方法來(lái)識(shí)別 12306 等驗(yàn)證碼也是完全相同的原理。
10. 本節(jié)代碼
本節(jié)代碼地址為:https://github.com/Python3WebSpider/CrackTouClick。
11. 結(jié)語(yǔ)
本節(jié)我們通過(guò)在線打碼平臺(tái)輔助完成了驗(yàn)證碼的識(shí)別,這種識(shí)別方法非常強(qiáng)大,幾乎任意的驗(yàn)證碼都可以識(shí)別,如果遇到難題,借助于打碼平臺(tái)無(wú)疑是一個(gè)極佳的選擇。
- 用Python爬蟲(chóng)破解滑動(dòng)驗(yàn)證碼的案例解析
- python網(wǎng)絡(luò)爬蟲(chóng)實(shí)現(xiàn)發(fā)送短信驗(yàn)證碼的方法
- Python爬蟲(chóng)爬取ts碎片視頻+驗(yàn)證碼登錄功能
- python爬蟲(chóng)如何解決圖片驗(yàn)證碼
- Python爬蟲(chóng)模擬登陸嗶哩嗶哩(bilibili)并突破點(diǎn)選驗(yàn)證碼功能
- Python3爬蟲(chóng)里關(guān)于識(shí)別微博宮格驗(yàn)證碼的知識(shí)點(diǎn)詳解
- Python3爬蟲(chóng)關(guān)于識(shí)別檢驗(yàn)滑動(dòng)驗(yàn)證碼的實(shí)例
- Python3爬蟲(chóng)中識(shí)別圖形驗(yàn)證碼的實(shí)例講解
- Python3網(wǎng)絡(luò)爬蟲(chóng)開(kāi)發(fā)實(shí)戰(zhàn)之極驗(yàn)滑動(dòng)驗(yàn)證碼的識(shí)別
- python爬蟲(chóng)解決驗(yàn)證碼的思路及示例
- Python爬蟲(chóng)實(shí)現(xiàn)驗(yàn)證碼登錄代碼實(shí)例
- python爬蟲(chóng)之驗(yàn)證碼篇3-滑動(dòng)驗(yàn)證碼識(shí)別技術(shù)
- python爬蟲(chóng)之自動(dòng)登錄與驗(yàn)證碼識(shí)別
- Python爬蟲(chóng)爬驗(yàn)證碼實(shí)現(xiàn)功能詳解
- Python爬蟲(chóng)模擬登錄帶驗(yàn)證碼網(wǎng)站
- 爬蟲(chóng)Python驗(yàn)證碼識(shí)別入門
相關(guān)文章
通過(guò)案例解析python鴨子類型相關(guān)原理
這篇文章主要介紹了通過(guò)案例解析python鴨子類型相關(guān)原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10Python常見(jiàn)讀寫(xiě)文件操作實(shí)例總結(jié)【文本、json、csv、pdf等】
這篇文章主要介紹了Python常見(jiàn)讀寫(xiě)文件操作,結(jié)合實(shí)例形式總結(jié)分析了Python常見(jiàn)的各種文件讀寫(xiě)操作,包括文本、json、csv、pdf等文件的讀寫(xiě)與相關(guān)注意事項(xiàng),需要的朋友可以參考下2019-04-04Python操作MySQL數(shù)據(jù)庫(kù)9個(gè)實(shí)用實(shí)例
這篇文章主要介紹了Python操作MySQL數(shù)據(jù)庫(kù)9個(gè)實(shí)用實(shí)例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-12-12tensorflow-gpu安裝的常見(jiàn)問(wèn)題及解決方案
這篇文章主要介紹了tensorflow-gpu安裝的常見(jiàn)問(wèn)題及解決方案,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧,需要的朋友可以參考下2020-01-01Python技巧匿名函數(shù)、回調(diào)函數(shù)和高階函數(shù)
本文分享的是Python技巧匿名函數(shù)、回調(diào)函數(shù)和高階函數(shù),我們?cè)赑ython中使用lambda表達(dá)式來(lái)使用匿名函數(shù),回調(diào)函數(shù)即callback,先寫(xiě)一個(gè)函數(shù),讓預(yù)先寫(xiě)好的系統(tǒng)來(lái)調(diào)用,一個(gè)函數(shù)可以作為參數(shù)傳給另外一個(gè)函數(shù),或者一個(gè)函數(shù)的返回值為另外一個(gè)函數(shù),滿足其一則為高階函數(shù)2021-12-12