驗證碼是爬蟲程序繞不過的坎,有各種各樣的驗證碼擋在前進的道路上,比如本文將要重點介紹的旋轉驗證碼,網上能找到不少關于這種驗證碼的逆向方法,整體思路都是一樣的,首先需要通過深度學習模型識別出圖片的旋轉角度,接下來逆向分析加密旋轉角度的一系列過程的js代碼,根據逆向出的過程構造出對應的參數,模擬驗證碼驗證接口調用實現旋轉驗證碼的識別。
不得不說,獨自搞定這一切相當耗時、耗力,而且還可能無功而返,怪不得逆向會經常伴隨著掉頭發的調侃,即使參照網上大佬們的技術文章,真正實踐起來才發現每走一步都可能有坑,有可能是平臺反爬策略更新導致和原文已不一致,也可能因為內容比較敏感導致關鍵細節被故意隱藏,還可能是技術實力欠缺等等。總之,這種逆向的方法讓很多人倍感無力,也許硬著頭皮研究下去最終可以搞定,但肯定需要花費不少的時間,而時間往往是不夠用的。
這里提出另外一種經過驗證可行的解決方案,那就是直接模擬用戶鼠標操作去拖動滑塊實現旋轉驗證碼識別(其他驗證碼也可以使用這個思路)。簡單分析下下面的旋轉碼操作就可以發現滑塊滑到頭,圖片就旋轉了一圈360°,它們之間是線性關系,可以計算出這個比例關系,一旦確定了圖片的旋轉角度就可以根據這個比例關系換算出滑塊滑動的距離,然后模擬拖動滑塊就完成了旋轉驗證碼的驗證。
這種處理驗證碼的方式完全不需要去逆向分析前端代碼,完全是站在用戶的視角在操作,當然它顯得不夠極客,可能性能也稍差點,但是真的不會掉太多頭發,關鍵是它可以解決問題,不管黑貓白貓,能抓老鼠就是好貓。按照這個思路的話,只需要重點解決下面幾個問題:
這一步的目的是提取旋轉驗證碼圖片數據,用于接下來使用深度學習模型識別旋轉角度。可以通過JavaScript代碼創建canvas畫布并繪制驗證碼圖像的方式來獲取圖片數據,如果你使用selenium、playwright這樣的自動化框架的話,它們都支持直接執行js代碼并獲取返回結果。這里需要注意的地方,一是圖像元素需要設置允許跨域,否則無法獲取到圖片數據,而且設置跨域屬性會觸發重新請求圖片,如果設置跨域后立刻繪制圖像是獲取不到數據的,需要等待響應圖片渲染完成。另外一個就是canvas.toDataURL需要指定圖片格式為png,因為jpeg是不支持透明背景的,使用jpeg格式會導致旋轉角度識別庫識別旋轉角度完全錯誤。
// img_selector表示驗證碼圖片選擇器var imgelm=document.querySelector(img_selector);// 設置允許跨域,否則無法獲取圖片數據// TIP:設置跨域后會觸發重新請求圖片,// 立刻獲取圖片尺寸結果為全0,需要等待一段時間重新獲取imgelm.setAttribute("crossOrigin","anonymous");var canvas = document.createElement('canvas');var ctx = canvas.getContext('2d');canvas.width=imgelm.naturalWidth;canvas.height=imgelm.naturalHeight;ctx.drawImage(imgelm, 0, 0);// 注意:jpeg格式不支持透明背景,這里使用png格式var dataURL = canvas.toDataURL('image/png');return dataURL;
關于旋轉角度識別,可以使用https://github.com/Starry-OvO/rotate-captcha-crack這個模型,這里通過運行server.py開啟一個web服務,通過調用接口,傳入圖片數據會返回識別出的旋轉角度。
(使用指導參考:https://cloud.tencent.com/developer/article/2418786)
不過,由于百度旋轉驗證碼圖片已經升級,圖片全部使用AI生成,更不易識別,當前的模型識別成功率有點低,不過可以通過增加重試來規避這個問題,如果你對深度學習比較熟悉的話也可以使用它的模型重新訓練最新的驗證碼圖片。
另外,百度除了會出現旋轉驗證碼之外,有時候也會出現其他類型驗證,比如滑塊驗證碼,這種情況就需要同時處理滑塊驗證碼和旋轉驗證碼,思路也是一樣的,至于滑塊驗證碼的識別可以使用ddddocr這個庫(https://gitee.com/fkgeek/ddddocr),官網文檔給出了詳細的使用方法。
不管是滑塊驗證碼還是旋轉驗證碼,識別出了圖片滑塊的距離、旋轉角度之后都可以簡單地通過線性關系得出拖動滑塊的距離,接下來就是模擬滑塊拖動指定距離就可以了,下面的js代碼實現了模擬拖動滑塊的功能。代碼中滑動距離僅給出示例,實際運行時請改為換算后的動態值。
() => { // selector:滑塊選擇器 offsetX: 滑動距離 function slide(selector, offsetX) { // 滑塊定位 let slider = document.querySelector(selector); // 計算滑塊矩形區域對角坐標 let rect = slider.getBoundingClientRect(), x0 = rect.x || rect.left, y0 = rect.y || rect.top, x1 = x0 + offsetX, y1 = y0; // 模擬鼠標按下動作 let mousedown = document.createEvent('MouseEvents'); mousedown.initMouseEvent('mousedown', true, true, window, 0, x0, y0, x0, y0, false, false, false, false, 0, null); slider.dispatchEvent(mousedown); //模擬鼠標拖動動作,將滑塊移動距離簡單拆分為4個相同距離的動作 let mousemove = document.createEvent('MouseEvents'); mousemove.initMouseEvent('mousemove', true, true, window, 0, x0+offsetX/4, y1, x0+offsetX/4, y1, false, false, false, false, 0, null); slider.dispatchEvent(mousemove); mousemove.initMouseEvent('mousemove', true, true, window, 0, x0+offsetX/2, y1, x0+offsetX/2, y1, false, false, false, false, 0, null); slider.dispatchEvent(mousemove); mousemove.initMouseEvent('mousemove', true, true, window, 0, x0+3*offsetX/4, y1, x0+3*offsetX/4, y1, false, false, false, false, 0, null); slider.dispatchEvent(mousemove); mousemove.initMouseEvent('mousemove', true, true, window, 0, x0+offsetX, y1, x0+offsetX, y1, false, false, false, false, 0, null); slider.dispatchEvent(mousemove); // 模擬鼠標釋放動作 let mouseout = document.createEvent('MouseEvents'); mouseout.initMouseEvent('mouseup', true, true, window, 0, x1, y1, x1, y1, false, false, false, false, 0, null); slider.dispatchEvent(mouseout); } // 執行滑塊拖動,以下distance和滑塊選擇器只是示例,根據實際情況進行調整 var distance = 200; slide('div.passMod_slide-btn', distance);}
最后,展示一下通過上面的思路使用playwright實現的旋轉驗證碼的識別過程,本次出現了兩次驗證碼,第一次是滑塊驗證碼,通過后又出現了旋轉驗證碼,可以發現旋轉驗證碼識別了3次才成功,就是因為模型對于最新的百度旋轉驗證碼圖片角度識別率變差導致的,實現上通過增加重試次數進行規避。經測試,無界面模式也可以正常運行。
參考文獻:
[1]https://cloud.tencent.com/developer/article/2418786
[2]https://github.com/Starry-OvO/rotate-captcha-crack
[3]https://gitee.com/fkgeek/ddddocr
[4]https://blog.csdn.net/m0_58618019/article/details/132918404
本文鏈接:http://www.tebozhan.com/showinfo-26-101270-0.html不掉頭發“逆向”旋轉驗證碼
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 說說MQ延遲隊列實現原理?
下一篇: 我們一起聊聊 Nginx 后端長連接