Selenium webdriver:修改navigator.webdriver标志以防止硒检测

Aja*_*nth 10 java selenium webdriver selenium-webdriver webdriver-w3c-spec

我正在尝试使用selenium和chrome在网站中自动执行一项非常基本的任务,但不知何故,网站检测到chrome由硒驱动并阻止每个请求.我怀疑该网站依赖于一个暴露的DOM变量,如/sf/answers/2933311741/来检测selenium驱动的浏览器.

我的问题是,有没有办法让navigator.webdriver标志为假?我愿意在修改之后尝试重新编译硒源,但我似乎无法在存储库中的任何地方找到NavigatorAutomationInformation源https://github.com/SeleniumHQ/selenium

任何帮助深表感谢

PS:我还从https://w3c.github.io/webdriver/#interface尝试了以下内容

Object.defineProperty(navigator, 'webdriver', {
    get: () => false,
  });
Run Code Online (Sandbox Code Playgroud)

但它只在初始页面加载后更新属性.我认为该网站在我的脚本执行之前检测到该变量.

010*_*101 64

铬驱动程序

终于用一个简单的标志发现了这个简单的解决方案!:)

--disable-blink-features=AutomationControlled
Run Code Online (Sandbox Code Playgroud)

navigator.webdriver=true将不再显示该标志集。

有关您可以禁用的内容列表,请在此处查看

  • 非常感谢!!python中的代码: `options.add_argument("--disable-blink-features=AutomationControlled")` (9认同)
  • 我的天啊!!它在 chromedriver 83 中对我有用。我尝试了很多解决方案,但这是唯一一个完美运行的解决方案。我使用 chromeOptions.add_argument 添加了 python。谢谢 (5认同)
  • 效果很好。但现在无头不起作用。有什么帮助吗? (3认同)
  • 绝对精彩!...对于使用 symfony/panther 和 chrome 的任何人,您可以通过设置 PANTHER_CHROME_ARGUMENTS="--disable-dev-shm-usage --disable-blink-features=AutomationControlled --window-size=1920x1080" 来实现此目的 (2认同)

小智 27

请勿使用 cdp 命令更改 webdriver 值,因为它会导致不一致,稍后可用于检测 webdriver。使用下面的代码,这将删除 webdriver 的任何痕迹。

options.add_argument("--disable-blink-features")
options.add_argument("--disable-blink-features=AutomationControlled")
Run Code Online (Sandbox Code Playgroud)


小智 16

要排除 2019 年 11 月 6 日更新的最高投票答案中提到的启用自动化开关的集合,截至 2020 年 4 月不再有效。相反,我收到以下错误:

ERROR:broker_win.cc(55)] Error reading broker pipe: The pipe has been ended. (0x6D)
Run Code Online (Sandbox Code Playgroud)

以下是截至 2020 年 4 月 6 日 Chrome 80 的运行情况。

之前(在 Chrome 控制台窗口中):

> navigator.webdriver
true
Run Code Online (Sandbox Code Playgroud)

蟒蛇示例:

options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features")
options.add_argument("--disable-blink-features=AutomationControlled")
Run Code Online (Sandbox Code Playgroud)

之后(在 Chrome 控制台窗口中):

> navigator.webdriver
undefined
Run Code Online (Sandbox Code Playgroud)


som*_*lse 14

之前(在浏览器控制台窗口中):

> navigator.webdriver
true
Run Code Online (Sandbox Code Playgroud)

变化(硒):

// C#
var options = new ChromeOptions();
options.AddExcludedArguments(new List<string>() { "enable-automation" });

// Python
options.add_experimental_option("excludeSwitches", ['enable-automation'])
Run Code Online (Sandbox Code Playgroud)

之后(在浏览器控制台窗口中):

> navigator.webdriver
undefined
Run Code Online (Sandbox Code Playgroud)

此功能不适用于ChromeDriver 79.0.3945.16及更高版本。在此处查看发行说明

  • 在 Firefox 中如何做同样的事情?/sf/ask/3998550601/ (3认同)

pgu*_*rio 14

现在,您可以使用 cdp 命令完成此操作:

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

driver.get(some_url)
Run Code Online (Sandbox Code Playgroud)

顺便说一句,你想退货undefinedfalse是一个死赠品。

  • 如今(即 Chrome 97.0.4692.71)它实际上是*错误*。无法评论 19 年 Chrome 是否为 false/未定义,但如果自(?)以来它发生了变化,我会感到惊讶 (4认同)

hld*_*dev 11

由于这个问题与硒有关,跨浏览器的覆盖解决方案navigator.webdriver是有用的。这可以通过在目标页面的任何 JS 运行之前修补浏览器环境来完成,但不幸的是,除了 chromium 之外,没有其他浏览器允许在文档加载之后和任何其他 JS 运行之前评估任意 JavaScript 代码(firefox 与 Remote Protocol很接近)。

\n

在修补之前,我们需要检查默认浏览器环境是什么样子的。在更改属性之前,我们可以使用以下命令查看它的默认定义Object.getOwnPropertyDescriptor()

\n
Object.getOwnPropertyDescriptor(navigator, \'webdriver\');\n// undefined\n
Run Code Online (Sandbox Code Playgroud)\n

因此,通过这个快速测试,我们可以看到webdriver属性未在navigator. 它实际上定义在Navigator.prototype

\n
Object.getOwnPropertyDescriptor(Navigator.prototype, \'webdriver\');\n// {set: undefined, enumerable: true, configurable: true, get: \xc6\x92}\n
Run Code Online (Sandbox Code Playgroud)\n

更改拥有该属性的对象的属性非常重要,否则可能会发生以下情况:

\n
navigator.webdriver; // true if webdriver controlled, false otherwise\n// this lazy patch is commonly found on the internet, it does not even set the right value\nObject.defineProperty(navigator, \'webdriver\', {\n  get: () => undefined\n});\nnavigator.webdriver; // undefined\nObject.getOwnPropertyDescriptor(Navigator.prototype, \'webdriver\').get.apply(navigator);\n// true\n
Run Code Online (Sandbox Code Playgroud)\n

一个不太幼稚的补丁会首先针对正确的对象并使用正确的属性定义,但深入挖掘我们可以发现更多的不一致之处:

\n
const defaultGetter = Object.getOwnPropertyDescriptor(Navigator.prototype, \'webdriver\').get;\ndefaultGetter.toString();\n// "function get webdriver() { [native code] }"\nObject.defineProperty(Navigator.prototype, \'webdriver\', {\n  set: undefined,\n  enumerable: true,\n  configurable: true,\n  get: () => false\n});\nconst patchedGetter = Object.getOwnPropertyDescriptor(Navigator.prototype, \'webdriver\').get;\npatchedGetter.toString();\n// "() => false"\n
Run Code Online (Sandbox Code Playgroud)\n

完美的补丁不会留下任何痕迹,如果我们能够拦截对它的调用并更改返回值,而不是替换 getter 函数,那就太好了。JavaScript 通过Proxy applyhandler对此提供本机支持:

\n
const defaultGetter = Object.getOwnPropertyDescriptor(Navigator.prototype, \'webdriver\').get;\ndefaultGetter.apply(navigator); // true\ndefaultGetter.toString();\n// "function get webdriver() { [native code] }"\nObject.defineProperty(Navigator.prototype, \'webdriver\', {\n  set: undefined,\n  enumerable: true,\n  configurable: true,\n  get: new Proxy(defaultGetter, { apply: (target, thisArg, args) => {\n    // emulate getter call validation\n    Reflect.apply(target, thisArg, args);\n    return false;\n  }})\n});\nconst patchedGetter = Object.getOwnPropertyDescriptor(Navigator.prototype, \'webdriver\').get;\npatchedGetter.apply(navigator); // false\npatchedGetter.toString();\n// "function () { [native code] }"\n
Run Code Online (Sandbox Code Playgroud)\n

现在唯一不一致的是函数名称,不幸的是,无法覆盖本机表示中显示的函数名称toString(){ [native code] }但即便如此,它也可以传递通用正则表达式,通过查找其字符串表示形式的末尾来搜索欺骗性的浏览器本机函数。要消除这种不一致,您可以修补Function.prototype.toString并使其为您修补的所有本机函数返回有效的本机字符串表示形式。

\n

总而言之,在 Selenium 中它可以应用于:

\n
chrome.execute_cdp_cmd(\'Page.addScriptToEvaluateOnNewDocument\', {\'source\': """\n    Object.defineProperty(Navigator.prototype, \'webdriver\', {\n        set: undefined,\n        enumerable: true,\n        configurable: true,\n        get: new Proxy(\n            Object.getOwnPropertyDescriptor(Navigator.prototype, \'webdriver\').get,\n            { apply: (target, thisArg, args) => {\n                // emulate getter call validation\n                Reflect.apply(target, thisArg, args);\n                return false;\n            }}\n        )\n    });\n"""})\n
Run Code Online (Sandbox Code Playgroud)\n

playwright项目维护了 Firefox 和 WebKit 的一个分支,以添加浏览器自动化功能,其中之一相当于,但没有通信协议的 Python 实现,但可以从头开始实现Page.addScriptToEvaluateOnNewDocument

\n


Gil*_*gio 7

python 的简单破解:

options = webdriver.ChromeOptions()    
options.add_argument("--disable-blink-features=AutomationControlled")
Run Code Online (Sandbox Code Playgroud)


Deb*_*anB 5

你看对了.您提到的答案指向W3C编辑的2017年草案,该草案已在过去两年中发展.目前的实施严格地说:

标志被设置为当所述用户代理正在远程控制,其最初被设置为.webdriver-active truefalse

进一步,

Navigator includes NavigatorAutomationInformation;
Run Code Online (Sandbox Code Playgroud)

需要注意的是:

不应在WorkerNavigator上公开该接口.NavigatorAutomationInformation

接口被定义为:NavigatorAutomationInformation

interface mixin NavigatorAutomationInformation {
    readonly attribute boolean webdriver;
};
Run Code Online (Sandbox Code Playgroud)

如果设置了flag,则返回true,否则返回false.webdriver-active

最后,navigator.webdriver定义了一种协作用户代理的标准方法,以通知文档它由WebDriver控制,以便在自动化期间触发备用代码路径.

更改任何这些参数可能会阻止导航并检测到WebDriver实例.

  • 那么我们该怎么做呢?对不起,我没明白这一点。我使用python客户端。 (5认同)
  • @DebanjanB我还应该使用`--disable-blink-features`和`--disable-blink-features=AutomationControlled`吗? (3认同)
  • 这不再起作用了。他们修补了开关“enable-automation”和“useAutomationExtension”,现在它们的行为正确,显示 navigator.wedriver 为 true。此外,我无法确定这部分从未起作用: driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () =&gt; undefined})") (3认同)
  • 1 月 21 日,这些技术都不再起作用了。我感觉 chrome 更新后一切都停止工作了。 (3认同)
  • 打开新页面时 `navigator.webdriver` 仍然是 `true` (2认同)
  • 有人有 Firefox &gt;= 88 的等效版本吗?profile.set_preferences("dom.webdriver.enabled", False) 不再有效。 (2认同)

Eli*_*gas 5

终于解决了ChromeDriver的问题,Chrome大于v79。

ChromeOptions options = new ChromeOptions();
options.addArguments("--disable-blink-features");
options.addArguments("--disable-blink-features=AutomationControlled");
ChromeDriver driver = new ChromeDriver(options);
Map<String, Object> params = new HashMap<String, Object>();
params.put("source", "Object.defineProperty(navigator, 'webdriver', { get: () => undefined })");
driver.executeCdpCommand("Page.addScriptToEvaluateOnNewDocument", params);
Run Code Online (Sandbox Code Playgroud)

  • 你能在 python 中分享这个吗? (2认同)