眾所周知目前使用selenium打開瀏覽器訪問淘寶,會彈出登錄頁面,不管你是手動還是自動登錄一律都是在滑塊驗證碼時不通過,今天花了幾個小時分析了一下,也只是對其整體有了個認識

總體上淘寶的反爬蟲思路是:基於用戶身份的ua算法,來識別瀏覽器是正常狀態還是非正常狀態。
ua:UA的中文翻譯是用戶代理,全稱是User Agent,簡單來說是終端的環境信息如:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1
它是一個特殊字符串頭,使得服務器能夠識別客戶使用的操作系統及版本、CPU 類型、瀏覽器及版本、瀏覽器渲染引擎、瀏覽器語言、瀏覽器插件等
但是這只是一般意義上的ua參數,實際使用中ua代表了一個終端的標識,ID代表了一個用戶的標識,隨着網絡安全的深入,ua已經不再是一串環境的信息字符串,而是開發者單獨發開出來的一套甄別終端的算法,成為了單獨執行的js文件
當訪問淘寶登錄界面會發送一個POST請求,這個post請求中有一個關鍵信息ua

ua參數很長一串,看似像RSA加密過的,並且這個參數時刻變化着,兩次生成的ua都不相同:
只有前幾位是相同的,其他完全不同,這個post請求中有一個關鍵信息ua,至於ua怎么生成目前還未分析出,他的出處在全局對象window[UA_Opt.LogVal]、或者window["_n"],並且每次輸出都不一樣。

瀏覽器window對象,他是出於一個私有屬性_n,但是怎么做到每次輸出的值都不一樣的。

使用正常瀏覽器打開瀏覽器的,window.navigator.webdriver這個值為undefined,在JavaScript中undefined為未定義,即該值不存在,而false表示一布爾值。

而使用selenium打開的瀏覽器,這個值為true

所以淘寶就是根據這個值進行滑塊的彈出和不彈出,當拖動滑塊的時候,會有一個滑塊驗證的請求,請求中有個參數t

這個t參數就是上面所提到的ua,也就是在驗證滑塊是否正確的時候淘寶后台還會對ua驗證一番,檢驗是否為正確的標識,一切selenium打開的瀏覽器里面'browser': {'ie': False, 'chrome': True, 'webdriver': True},當然webdriver是比較關鍵的參考標准,除此還有幾十個其他異於正常瀏覽器的屬性,很明顯這些信息被加密在ua參數之中。淘寶后台在收到滑塊驗證信息的時候,會同時對ua經行驗證,所有含有webdriver=True的驗證都會被返回code=300。

現在我們大致就清楚了淘寶對selenium的檢測:通過本地的js算法生成ua,ua里面含有瀏覽器信息,甚至含有當前地址,當輸入完賬號后會把賬號和ua一起post給服務器,服務器解析ua后通過智能算法識別是否是常用登陸地、常用瀏覽器、環境有無異常,selenium打開的瀏覽器是異常瀏覽器,一定會返回滑塊驗證,當完成驗證后會再把ua和滑動的軌跡發給后台,后台在檢測ua,一旦含有異常信息就返回code=300,驗證失敗。
那么問題來了,怎么來避開滑塊驗證呢?
一、WebDriver規范
根據WebDriver規范(https://w3c.github.io/webdriver/#x4-interface)的描述,WebDriver定義了一個標准方法,以便於文檔(document)判斷當前瀏覽器處於自動化控制之中。
這個方法就是檢測window.navigator.webdriver的值,正常情況下其值為undefined,自動化控制下為true。注意,正常情況下不是false,在JavaScript中undefined為未定義,即該值不存在,而false表示一布爾值。
附上規范原文:
The webdriver-active flag is set to true when the user agent is under remote control. It is initially false.
Defines a standard way for co-operating user agents to inform the document that it is controlled by WebDriver, for example so that alternate code paths can be triggered during automation.
二、如何來解除這個規范呢
舊版本
在版本79.0.3945.16之前,可用如下方法:
from selenium import webdriver options = webdriver.ChromeOptions() options.add_argument("start-maximized") options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option("useAutomationExtension", False) driver = webdriver.Chrome(options=options) driver.get("YOUR_URL") # 在控制台中驗證window.navigator.webdriver的值為undefined。 driver.quit()
新版本
在版本79.0.3945.16之后,ChromeDriver修正了這一“問題”。
根據注記原文:
Resolved issue 3133: window.navigator.webdriver is undefined when "enable-automation" is excluded in non-headless mode (should be true) [Pri-2]
如何破解?
execute_cdp_cmd函數來幫忙!cdp即Chrome DevTools Protocal,Chrome開發者工具協議。
通過該函數在文檔加載前注入一段js代碼以消去webdriver值。
from selenium import webdriver driver = webdriver.Chrome() script = ''' Object.defineProperty(navigator, 'webdriver', { get: () => undefined }) ''' driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": script}) driver.get("YOUR_URL") # 在控制台中驗證window.navigator.webdriver的值為undefined。 driver.quit()
