天天看點

反反爬蟲(0) :還在用 selenium 裸爬嗎? 你已經被盯上了!破解WebDriver反爬蟲

文章目錄

    • selenium簡介
    • 反爬蟲
    • 反反爬蟲
      • 配置 Selenium 選項
      • 控制已打開的浏覽器
      • mitmproxy中間人
    • 待續...

selenium簡介

當我們使用 requests 抓取頁面的時候,得到的結果可能會和在浏覽器中看到的不一樣,正常顯示的頁面資料,使用 reuquests 卻沒有得到結果。這是因為 requests 擷取的都是原始 HTML 文檔,而浏覽器中的頁面則是經過 Javascript 資料處理後生成的結果,這些資料的來源有多種,可能是通過 AJax 加載的,也可能是經過 Javascript 和特定算法計算後生成的。

此時解決方法通常有兩種:

  • 深挖 Ajax 的邏輯,把接口位址和其加密參數構造邏輯完全找出來,再用 Python 複現,構造 Ajax請求
  • 通過模拟浏覽器的方式,繞過這個過程。

這裡我們主要介紹下第二種方式,模拟浏覽器爬取。

Selenium 是一個自動化測試工具,利用它可以驅動浏覽器執行特定的操作。比如點選,下拉等操作,同時還可以擷取浏覽器目前呈現的頁面源代碼,做到 所見即所得。對于一些使用 Javascript 動态渲染的頁面來說,此種抓取方式非常有效!

反反爬蟲(0) :還在用 selenium 裸爬嗎? 你已經被盯上了!破解WebDriver反爬蟲

反爬蟲

但是,使用 Selenium 調用 ChromeSriver 來打開網頁,還是與正常打開網頁有一定的差別的。現在很多網站都加上了對 Selenium 的檢測,來防止一些爬蟲的惡意爬取。

大多數情況下,檢測的基本原理是檢測目前浏覽器視窗下的

window.navigator

對象是否包含

webdriver

這個屬性。在正常使用浏覽器的情況下,這個屬性是

undefined

,然後一旦我們使用了 selenium,這個屬性就被初始化為

true

,很多網站就通過 Javascript 判斷這個屬性實作簡單的反 selenium爬蟲。

這時候我們可能想到通過 Javascript 直接把這個 webdriver 屬性置空,比如通過調用

execute_script

方法來執行如下代碼:

這行 Javascript 的确可以把 webdriver 屬性置空,但是 execute_script 調用這行 Javascript 語句實際上是在頁面加載完畢之後才執行的,執行得太晚了,網站早在頁面渲染之前就已經對 webdriver 屬性進行了檢測,所有用上述方法并不能達到效果。

反反爬蟲

基于上邊舉例的反爬措施,我們主要可以使用如下方法解決:

配置 Selenium 選項

但是

ChromeDriver 79.0.3945.36

版本修改了非無頭模式下排除 “啟用自動化” 時

window.navigator.webdriver

是未定義的問題,要想正常使用,需要把 Chrome 復原 79 之前的版本,并找到對應的 ChromeDriver 版本,這樣才可以!

當然,大家也可以參考

CDP(Chrome Devtools-Protocol)

文檔,使用

driver.execute_cdp_cmd

在 selenium 中調用

CDP

的指令。下述代碼隻需要執行一次,之後隻要不關閉這個 driver 開啟的視窗,無論打開多少網址,它都會在網站自帶的所有 JS 之前執行這個語句,進而達到隐藏 webdriver 的目的。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options


options = Options()
# 隐藏 正在受到自動軟體的控制 這幾個字
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)

driver = webdriver.Chrome(executable_path=r"E:\chromedriver\chromedriver.exe", options=options)

# 修改 webdriver 值
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
})

driver.get('https://www.baidu.com')
           

另外如下配置也可以去除 webdriver 特征

options = Options()
options.add_argument("--disable-blink-features")
options.add_argument("--disable-blink-features=AutomationControlled")
           

控制已打開的浏覽器

既然使用 selenium 打開的浏覽器存在一些特定參數,那麼我們可以另辟蹊徑,直接手動打開一個真實的浏覽器,然後再使用 selenium 控制不就可以了嗎!

  • 利用 Chrome DevTools 協定打開一個浏覽器,它允許客戶檢查和調試 Chrome 浏覽器

    (1)關閉所有打開的 Chrome 視窗

    (2)打開 CMD,在指令行中輸入指令:

    # 此處 Chrome 的路徑需要修改為你本機的 Chrome 安裝位置
    # --remote-debugging-port 指定任何打開的端口
    "C:\Program Files(x86)\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222
               
    若路徑正确,此時會打開一個新的 Chrome 視窗
  • 使用 selenium 連接配接這個打開的 Chrome 視窗
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    
    options = Options()
    # 此處端口需要與上一步中使用的端口保持一緻
    # 其它大多部落格此處使用 127.0.0.1:9222, 經測試無法連接配接, 建議采用 localhost:9222
    # 具體原因參見: https://www.codenong.com/6827310/
    options.add_experimental_option("debuggerAddress", "localhost:9222")
    
    driver = webdriver.Chrome(executable_path=r"E:\chromedriver\chromedriver.exe", options=options)
    
    driver.get('https://www.baidu.com')
               

但是使用本方法也存在一些弊端:

浏覽器一旦啟動,selenium中對浏覽器的配置就不在生效了,例如

–-proxy-server

等,當然你也可以一開始啟動 Chrome 的時候就加上

mitmproxy中間人

mitmproxy

其實和

fiddler/charles

等抓包工具的原理有些類似,作為一個第三方,它會把自己僞裝成你的浏覽器向伺服器發起請求,伺服器傳回的 response 會經由它傳遞給你的浏覽器,你可以 通過編寫腳本來更改這些資料的傳遞,進而實作對伺服器的 “欺騙” 和對用戶端的 “欺騙”

部分網站采用單獨的 js 檔案來識别 webdriver 的結果,我們可以通過 mitmproxy 攔截識别 webdriver 辨別符的 js 檔案,并僞造正确的結果。

參考:使用 mitmproxy + python 做攔截代理

待續…

其實,不隻是 webdriver,selenium打開浏覽器後,還會有這些特征碼:

webdriver  
__driver_evaluate  
__webdriver_evaluate  
__selenium_evaluate  
__fxdriver_evaluate  
__driver_unwrapped  
__webdriver_unwrapped  
__selenium_unwrapped  
__fxdriver_unwrapped  
_Selenium_IDE_Recorder  
_selenium  
calledSelenium  
_WEBDRIVER_ELEM_CACHE  
ChromeDriverw  
driver-evaluate  
webdriver-evaluate  
selenium-evaluate  
webdriverCommand  
webdriver-evaluate-response  
__webdriverFunc  
__webdriver_script_fn  
__$webdriverAsyncExecutor  
__lastWatirAlert  
__lastWatirConfirm  
__lastWatirPrompt
...
           

如果你不相信,我們可以來做一個實驗,分别使用 正常浏覽器,

selenium+Chrome

selenium+Chrome headless

打開這個網址:https://bot.sannysoft.com/

反反爬蟲(0) :還在用 selenium 裸爬嗎? 你已經被盯上了!破解WebDriver反爬蟲

當然,這些例子并不是為了打擊各位的自信,僅僅是希望大家不要學會了部分技術就開始沾沾自喜,時刻保持一顆赤子之心,懷着對技術的熱情繼續前進。爬蟲與反爬蟲這場沒有硝煙的戰争,還在繼續 …