I'm trying to automate a very basic task in a website using selenium and chrome but somehow the website detects when chrome is driven by selenium and blocks every request. I suspect that the website is relying on an exposed DOM variable like this one https://stackoverflow.com/a/41904453/648236 to detect selenium driven browser.
My question is, is there a way I can make the navigator.webdriver flag false? I am willing to go so far as to try and recompile the selenium source after making modifications, but I cannot seem to find the NavigatorAutomationInformation source anywhere in the repository https://github.com/SeleniumHQ/selenium
Any help is much appreciated
P.S: I also tried the following from https://w3c.github.io/webdriver/#interface
Object.defineProperty(navigator, 'webdriver', { get: () => false, });
But it only updates the property after the initial page load. I think the site detects the variable before my script is executed.
It 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. The navigator. webdriver property is true when in: Chrome.
The answer is YES! Websites can detect the automation using JavaScript experimental technology navigator. webdriver in the navigator interface. If the website is loaded with automation tools like Selenium, the value of navigator.
execute_cdp_cmd()
: With the availability of execute_cdp_cmd(cmd, cmd_args)
command now you can easily execute google-chrome-devtools commands using Selenium. Using this feature you can modify the navigator.webdriver
easily to prevent Selenium from getting detected.
To prevent Selenium driven WebDriver getting detected a niche approach would include either/all of the below mentioned steps:
Adding the argument --disable-blink-features=AutomationControlled
from selenium import webdriver options = webdriver.ChromeOptions() options.add_argument('--disable-blink-features=AutomationControlled') driver = webdriver.Chrome(options=options, executable_path=r'C:\WebDrivers\chromedriver.exe') driver.get("https://www.website.com")
You can find a relevant detailed discussion in Selenium can't open a second page
Rotating the user-agent through execute_cdp_cmd()
command as follows:
#Setting up Chrome/83.0.4103.53 as useragent driver.execute_cdp_cmd('Network.setUserAgentOverride', {"userAgent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.53 Safari/537.36'})
Change the property value of the navigator
for webdriver to undefined
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
Exclude the collection of enable-automation
switches
options.add_experimental_option("excludeSwitches", ["enable-automation"])
Turn-off useAutomationExtension
options.add_experimental_option('useAutomationExtension', False)
Clubbing up all the steps mentioned above and effective code block will be:
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, executable_path=r'C:\WebDrivers\chromedriver.exe') driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") driver.execute_cdp_cmd('Network.setUserAgentOverride', {"userAgent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.53 Safari/537.36'}) print(driver.execute_script("return navigator.userAgent;")) driver.get('https://www.httpbin.org/headers')
As per the W3C Editor's Draft the current implementation strictly mentions:
The
webdriver-active
flag is set totrue
when the user agent is under remote control which is initially set tofalse
.
Further,
Navigator includes NavigatorAutomationInformation;
It is to be noted that:
The
NavigatorAutomationInformation
interface should not be exposed on WorkerNavigator.
The NavigatorAutomationInformation
interface is defined as:
interface mixin NavigatorAutomationInformation { readonly attribute boolean webdriver; };
which returns true
if webdriver-active
flag is set, false otherwise.
Finally, the navigator.webdriver
defines a standard way for co-operating user agents to inform the document that it is controlled by WebDriver, so that alternate code paths can be triggered during automation.
Caution: Altering/tweaking the above mentioned parameters may block the navigation and get the WebDriver instance detected.
As of the current implementation an ideal way to access a web page without getting detected would be to use the ChromeOptions()
class to add a couple of arguments to:
enable-automation
switchesuseAutomationExtension
through an instance of ChromeOptions
as follows:
Java Example:
System.setProperty("webdriver.chrome.driver", "C:\\Utility\\BrowserDrivers\\chromedriver.exe"); ChromeOptions options = new ChromeOptions(); options.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation")); options.setExperimentalOption("useAutomationExtension", false); WebDriver driver = new ChromeDriver(options); driver.get("https://www.google.com/");
Python Example
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=r'C:\path\to\chromedriver.exe') driver.get("https://www.google.com/")
Ruby Example
options = Selenium::WebDriver::Chrome::Options.new options.add_argument("--disable-blink-features=AutomationControlled") driver = Selenium::WebDriver.for :chrome, options: options
1: Applies to Selenium's Python clients only.
2: Applies to Selenium's Python clients only.
3: Applies to Selenium's Python clients only.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With