前言
正常的登入機制中有一個環節是顯示一張驗證碼圖片,請使用者輸入圖片中的驗證碼,來達到阻擋機器人 (爬蟲) 登入的效果。但這並不能阻止以爬蟲為樂的我們,我們可以在需要輸入驗證碼的時候,將驗證碼截圖並顯示在跳出對話框,請使用者手動輸入驗證碼。成功登入後,剩下的工作就可交由爬蟲繼續執行。
然而,對驗證碼圖片的連結發出一個資源請求,正常來說會回傳不同於前一次的驗證碼圖片,因此我們不能只抓 img 標籤中的 src 然後重新發出請求來下載該圖片。而是應直接下載當前頁面所顯示的圖片,這篇文章紀錄如何使用 Selenium 在不重新發出請求的情形下,下載當前 img 標籤內的圖片。
環境
- Python 3.8.5
- matplotlib 3.4.2
- selenium 3.140.0
原因說明
直接舉實例來觀察,隨意以 網路郵局 介面中的 驗證碼連結 為例,同樣的連結重新整理後,會吐不一樣的圖片出來
若使用 urllib
或 requests
等套件去下載圖片,顯示給使用者輸入,這時取得的驗證碼圖片,一定不是正確的。要解決這個問題,直接從頁面抓當前的圖片是最佳解。
解決方法
想要解決這個問題還需要使用到 Javascript (js) 來協助。
先透過 js 在 Selenium 中取得 img 的內容,並以 Base64 格式回傳圖片內容到 Python 中,有了這個 Base64 圖片,甚麼都好辦,例如存檔、顯示在 tkinter 視窗或更多其他種應用。
若想要知道還能如何利用透過 Selenium 取得的驗證碼圖片,歡迎參考實際範例 [爬蟲] Selenium+Tkinter 製作具有驗證碼的網站登錄器 !
取得圖片 Base64 格式
使用 js 進行 DOM 操作,每一個步驟詳細說明盡在註解中
1 | // 創建一個 canvas 元素 |
得到的資料會像下面這樣的形式呈現,半形逗號之前為圖片的資訊,例如格式為 image/png
且以 base64 編碼,半形逗號後面的則是編碼後的資料 (data)
1 | data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAI4AAAAw...(ignored) |
回傳 Base64 圖片
我們已經會使用 js 來取得 Base64 格式的圖片了,接下來就是要將它回傳到 Python 之中,Selenium 提供一個函數 execute_async_script
讓我們可以在當前頁面運行 js 腳本,並將結果回傳到 Python 中
1 | from selenium import webdriver |
callback
:函式的最後一個參數 (arguments[arguments.length - 1]
) 為 JavaScript Callback 函式,將要回傳的資料作為參數呼叫此函式,便能將資料回傳到 Python 之中。
若想查看是否真的是驗證碼的圖,可以使用 matplotlib
套件來顯示,
1 | import base64 |
結語
爬蟲爬的是 html 文件,因此 js、css 多少都要會,這個例子關鍵在於 js 的使用,用以取得 img 標籤 Base64 格式圖片,這是單純 Python 無法達到的功能。