轉自: https://zhuanlan.zhihu.com/p/55956954web
當使用selenium去某寶或其餘網站進行爬蟲或者模擬登錄時,會出現滑動驗證碼,而且不管是用ActionChains滑仍是手動滑,都會很委婉的告訴你「哎呀網絡錯誤,請刷新」等等。why?chrome
通過科.xx學.xx上xx.網,查閱衆多資料,發現seleniumyou 有一些特徵值, 例以下面:瀏覽器
window.navigator.webdriver
window.navigator.languages
window.navigator.plugins.length網絡
其中最主要的特徵值就是webdriver這一項。app
partial interface Navigator { readonly attribute boolean webdriver; };
Navigator接口的webdriver IDL屬性必須返回webdriver-active標誌的值,該標誌默認值爲false或者undefined。less
此屬性容許網站肯定用戶代理受WebDriver控制,並可用於幫助緩解壓力,拒絕服務攻擊。dom
直接取自2017 W3C Editor的WebDriver草案。這在很大程度上意味着,至少,將來selenium驅動程序迭代將被識別以防止濫用。工具
檢測方法:網站
檢查→Console→輸入"window.navigator.webdriver"lua
正常狀況下爲false或者undefined(根據瀏覽器穩定)
若是咱們使用selenium自動化運行瀏覽器,而後在利用上述檢測方法,其值會是true
因而我開始摸索網站對於該特徵值的檢測方法:
經過F12全局搜索,我發如今index.js中有webdriver的字段:
另外,還有兩個參數能夠揭示使用了chromedriver:
1.「navigator.plugins.length」此參數能夠檢測selenium的headless模式,headless模式下爲0,因此能夠添加假的值來規避檢測;
2.「navigator.languages」確保將此參數設置爲chrome的默認值[「en-US」,「en」,"es"]
--------------------------------------------------------------------------------------------
ok,接下來咱們要作的:
selenium被檢測的突破——修改webdriver的特徵值
經過科,學,上,網,有一個方法是:
經過16進制編輯工具將chromedirver的$cdc_和$wdc_這兩個變量名稱修改掉,可是我沒有嘗試,這裏不作贅述,有興趣可自行嘗試。
我所使用的是利用mitmproxy經過代碼注入的方式進行修改webdriver的值。
'Object.defineProperties(navigator,{webdriver:{get:() => false}});'
咱們須要在index.js中的檢測webdriver前面注入一段代碼,將webdriver值改成替換爲false。
1.爲何不使用selenium中的executeScript()
執行js代碼呢?
由於executeScript()是在網頁渲染完成後才執行。而檢測webdriver是在網頁渲染過程當中檢測。因此無效。
2.手動在console修改webdriver值?
此方法治標不治本。只是臨時修改了webdriver值。而且,你須要在檢測瀏覽器指紋的XHR以前修改,纔能有效。
-----------------------------------------------------------------------------------------------
總結:
1.網站經過「navigator.webdriver,navigator.languages,navigator.plugins.length」等參數瀏覽器指紋來檢測是否使用了selenium+webdriver。其中,之主要的特徵爲「webdriver」是否爲true;
注意,在老版本的火狐瀏覽器會把webdriver直接用Attribute的形式寫入,所以可使用檢測
window.document.documentElement.getAttribute(「webdriver」)
是否爲true的方法,檢測是否使用了selenium。
2.修改chromedriver源碼;
3.使用mitmproxy或fiddler作代碼注入;
4.使用其餘方法攔截髮送回瀏覽器指紋的XHR
-----------------------------------------------------------------------------------------------
附一些網站檢測selenium的示例
runBotDetection = function () {
var documentDetectionKeys = [
"__webdriver_evaluate",
"__selenium_evaluate",
"__webdriver_script_function",
"__webdriver_script_func",
"__webdriver_script_fn",
"__fxdriver_evaluate",
"__driver_unwrapped",
"__webdriver_unwrapped",
"__driver_evaluate",
"__selenium_unwrapped",
"__fxdriver_unwrapped",
];
var windowDetectionKeys = [
"_phantom",
"__nightmare",
"_selenium",
"callPhantom",
"callSelenium",
"_Selenium_IDE_Recorder",
];
for (const windowDetectionKey in windowDetectionKeys) {
const windowDetectionKeyValue = windowDetectionKeys[windowDetectionKey];
if (window[windowDetectionKeyValue]) {
return true;
}
};
for (const documentDetectionKey in documentDetectionKeys) {
const documentDetectionKeyValue = documentDetectionKeys[documentDetectionKey];
if (window['document'][documentDetectionKeyValue]) {
return true;
}
};
for (const documentKey in window['document']) {
if (documentKey.match(/\$[a-z]dc_/) && window['document'][documentKey]['cache_']) {
return true;
}
}
if (window['external'] && window['external'].toString() && (window['external'].toString()['indexOf']('Sequentum') != -1)) return true;
if (window['document']['documentElement']['getAttribute']('selenium')) return true;
if (window['document']['documentElement']['getAttribute']('webdriver')) return true;
if (window['document']['documentElement']['getAttribute']('driver')) return true;
return false;
};
try {
if (window.document.documentElement.getAttribute("webdriver")) return !+[]
} catch (IDLMrxxel) {}
try {
if ("_Selenium_IDE_Recorder" in window) return !+""
} catch (KknKsUayS) {}
try {
if ("__webdriver_script_fn" in document) return !+""
改寫特徵參數的js
// 改寫 `languages`
Object.defineProperty(navigator, "languages", {
get: function() {
return ["en", "es"];
}
});
//改寫 `plugins`
Object.defineProperty(navigator, "plugins", {
get: () => new Array(Math.floor(Math.random() * 6) + 1),
});
// 改寫`webdriver`
Object.defineProperty(navigator, "webdriver", {
get: () => false,
});