動態網頁與靜態網頁最大的不同是資料是在什麼時間點取得的,動態網頁是在瀏覽器已經取得 HTML 後,才透過 JavaScript 在需要時動態地取得資料。因此,爬蟲程式也必須要考慮動態取得資料這件事情,才有辦法正確地找到想要的資料。「滑動驗證碼(Slider Captcha)」是驗證碼機制當中常見的典型,也是防範爬蟲程式中一種難纏的對手。這一篇文章將會利用 Python 、opencv 與 Selenium 三個工具,示範如何拆解和模擬滑動驗證碼。
常見的網頁驗證碼類型與原理
你在瀏覽網頁的時候,有看過這些驗證機制嗎?網頁驗證碼的專業術語稱為「CAPTCHA 」(全名是 Completely Automated Public Turing test to tell Computers and Humans Apart 自動判別電腦與人類的公開圖靈測試),是目前在網頁當中常見的一種驗證機制,用來判斷惡意的使用者干擾與攻擊。目前常見的 CAPTCHA 方法有以下幾種:
- 信件驗證碼/簡訊驗證碼
- 圖形驗證碼
- 問題驗證碼
- 行為驗證碼
reCAPTCHA 計畫目前是由 Google 主要發展的驗證機制,最早是由 CMU 發起的 。reCAPTCHA 透過不同的情境讓人類回答,並藉此來幫助幫助文件數位化的進行。這個計畫將紙本掃描後無法被辨識文字顯示在問題中,讓人類在回答問題也能加以利用。
利用 Python 處理「滑動程式碼」的思路
而在「圖形驗證碼」當中,有一種常見的變形稱為「滑動驗證碼」。滑動驗證碼會動態的更新圖片與缺塊,並且要求使用者將缺塊移動到圖片中的特定位置才能通過判斷,如圖所示:
對於爬蟲的開發者而言,滑動驗證碼的確是一個蠻大的門檻。如何爬蟲程式可以讀得懂驗證碼,並且進一步模擬其行為都需要對網頁運作有一定的熟悉程度才行。接下來,就讓我們透過實作範例一起來體驗滑動程式碼的解決思路,我們可以分成兩個大區塊:
- ① 利用 Python + opencv 拆解缺塊位置
- ② 利用 Python + Selenium 模擬滑動行為
① 利用 Python + opencv 拆解缺塊位置
先手動把「背景圖」下載到本地端電腦,再試著利用圖像識別的方法試著找出位置。
(1)利用 cv2 將圖片讀取到程式中
OpenCV(Open Source Computer Vision Library)是用於電腦視覺的處理套件,在 Python 可以使用 opencv-python 與 cv2 進行安裝/載入。第一步,我們先利用 cv2.imread(…) 把圖片讀到程式中,並且利用 cv2.cvtColor 進行顏色轉換(原始圖片有誤差):
1 | from matplotlib import pyplot as plt |
(2)判斷圖片中的物體邊緣輪廓
Canny 是圖形識別中用來作邊緣偵測(Edge Detection)的方法,細節的參數細節可以看官方文件。Canny 方法能將原始圖片轉成灰階之後,輸出包含邊緣範圍的黑白影像:
1 | canny = cv2.Canny(image, 300, 300) |
可以從結果中看到除了區塊之後,也包含很多小的零散的區塊部分:
(3)取出缺塊所在的位置
接下來利用 cv2.findContours() 找出圖片中所有偵測到的區塊,把他標記成藍色的部分畫出來。從長度(w)跟寬度(h)可以判斷出哪一個區塊是圖片中真正的區塊,但圖片顏色太接近的情況下會增加判斷的難度。
1 | contours, hierarchy = cv2.findContours(canny, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) |
最終就可以得到缺塊所在的位置是 dx 和 dy 兩個變數:
1 | dx, dy # (202, 15) |
以這個例子來說,我們就可以得知缺塊距離最左邊距離 202 px 的偏移量。
② 利用 Python + Selenium 模擬滑動行為
第二段,我們會利用 Selenium 瀏覽器測試工具幫助我們「模擬使用者移動方塊」的行為。關於 Selenium 的動態網頁模擬,之前也有寫過這一篇分享文。
(1)打開瀏覽器前往網頁,下載原始圖片
先觀察一下網頁的組成,發現給定的範例網站是利用 Canvas 動態載入圖片實現滑動驗證碼的效果的:
接下來利用 Selenium 打開瀏覽器跳轉到網頁中,利用 JavaScript 的先將 Canvas 轉成圖片後再進行下載 。
1 | from selenium import webdriver |
這麼做就可以把原始圖片下載下來,搭配「① 利用 Python + opencv 拆解缺塊位置」可以得知需要移動的偏移量。
找出按鈕元素
透過觀察網頁的結構,可以明確的找出需要被移動的方塊是位在 class = jigsaw__slider–ihcNg 的 div 元素(具體的找法,可以參考這一篇文章):
使用 Selenium 輕鬆選取:
1 | btn = browser.find_element__class_name("jigsaw__slider--ihcNg") |
(2)模擬使用者拖拉方塊行為
最後一步,就可以利用剛剛找出來缺塊的位置及瀏覽器模擬的工具,把方塊移動到指定的偏移位置:
1 | move = ActionChains(browser) |
實戰!讓 Python 爬蟲也能讀得懂「滑動驗證碼」
在這個例子當中,除了實作滑動驗證碼的爬蟲之外,也弄了一個簡單的滑動驗證碼作為標的。最後的成果大概像這樣,從「打開網頁」 → 「下載圖片」 → 「解析位置」 → 「模擬滑動」的整個過程:
網頁爬蟲是資料收集的一種手法,不過面對於網頁技術的變化,爬蟲程式也有不同的應對策略。如果你在爬蟲實作上還遇到什麼問題,也歡迎留言分享你的觀察與解法 😃😃😃
Reference
[1] 驗證碼
[2] Captcha验证码有哪些分类?有什么作用?
[3] 使用 Python + Selenium 破解滑块验证码
嗨,我是維元,近期推出一個全新型態的【 Python 資料科學教學實戰營 】,結合多元教學形式及豐富課程經驗幫助你更有效地學習。新課程「 Python 程式設計基礎養成 」正在早鳥募資中,歡迎你一起加入資料領域!誠摯的邀請你跟著我們一起從 Python 入門開始,走進資料科學的世界 🙌
📍 報名頁面: https://dscareer.kolable.app/
📍 報名頁面: https://dscareer.kolable.app/
📍 報名頁面: https://dscareer.kolable.app/
License
本著作由Chang Wei-Yaun (v123582)製作,
以創用CC 姓名標示-相同方式分享 3.0 Unported授權條款釋出。