在《一日一技:如何正確移除Selenium中window.navigator.webdriver的值》一文中,咱們介紹了在當時可以正確從Selenium啓動的Chrome瀏覽器中移除window.navigator.webdriver
的方法。javascript
後來時過境遷,Chrome升級了版本,致使當時的方法已經失效。以下圖所示:html
針對最新版本的Chrome,咱們應該如何正確隱藏這個參數呢?java
在那篇文章裏面,我罵了一種掩耳盜鈴的方式:python
打開網頁,而後經過執行以下 JavaScript 語句來隱藏window.navigator.webdriver
的值:git
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
複製代碼
我罵了這種方式爲掩耳盜鈴,是由於他們是在網頁已經加載完畢之後才運行這段 JavaScript 代碼的,可此時網站自身的 js 程序早就已經經過讀取window.navigator.webdriver
知道你如今使用模擬瀏覽器,你隱藏了又有什麼用呢?github
因此即便要執行這段 JavaScript 語句,也應該是在瀏覽器運行網站自帶的全部 JavaScript 以前。web
這也就是咱們如今的方案。chrome
可能有讀者會認爲,是否是經過寫 Chrome 瀏覽器的插件,讓插件裏面的 JavaScript 語句在網站頁面剛剛打開,尚未運行自帶的 JavaScript 以前運行。api
這種方式雖然能夠解決問題,但稍顯麻煩,咱們今天的方法很是簡單。就是使用 Google 的Chrome Devtools-Protocol(Chrome 開發工具協議)
簡稱CDP
。瀏覽器
咱們打開 CPD 的官方文檔,能夠看到以下的命令:
在每一個Frame 剛剛打開,尚未運行 Frame 的腳本前,運行給定的腳本。
經過這個命令,咱們能夠給定一段 JavaScript 代碼,讓 Chrome 剛剛打開每個頁面,尚未運行網站自帶的 JavaScript 代碼時,就先執行咱們給定的這段代碼。
那麼如何在 Selenium 中調用 CDP 的命令呢?實際上很是簡單,咱們使用driver.execute_cdp_cmd
。根據 Selenium 的官方文檔,傳入須要調用的 CDP 命令和參數便可:
因而咱們能夠寫出以下代碼:
from selenium.webdriver import Chrome
driver = Chrome('./chromedriver')
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """ Object.defineProperty(navigator, 'webdriver', { get: () => undefined }) """
})
driver.get('http://exercise.kingname.info')
複製代碼
運行效果以下圖所示:
完美隱藏window.navigator.webdriver
。而且,關鍵語句:
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """ Object.defineProperty(navigator, 'webdriver', { get: () => undefined }) """
})
複製代碼
只須要執行一次,以後只要你不關閉這個driver
開啓的窗口,不管你打開多少個網址,他都會自動提早在網站自帶的全部 js 以前執行這個語句,隱藏window.navigator.webdriver
。
若是有人運行上面的代碼,出現以下報錯:
那麼請升級你的 ChromeDriver。老版本的 Chrome + ChromeDriver 只能用之前的方法,不能用今天的方法。新版本的 Chrome + ChromeDriver 可使用今天的方法,但不能用老方法。正應了那句話:
上帝給你關上一扇門的時候,悄悄爲你開了一扇窗。
雖然使用以上代碼就能夠達到目的了,不過爲了實現更好的隱藏效果,你們也能夠繼續加入兩個實驗選項:
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=options, executable_path='./chromedriver')
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """ Object.defineProperty(navigator, 'webdriver', { get: () => undefined }) """
})
driver.get('http://exercise.kingname.info')
複製代碼