Selenium webdriver: Modifying navigator.webdriver flag to prevent selenium detection

前端 未结 10 828
既然无缘
既然无缘 2020-11-22 00:57

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.

相关标签:
10条回答
  • 2020-11-22 01:09

    First the update 1

    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.


    Preventing Detection 2

    To prevent Selenium driven WebDriver getting detected a niche approach would include either/all of the below mentioned steps:

    • 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)
      

    Sample Code 3

    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')
    

    History

    As per the W3C Editor's Draft the current implementation strictly mentions:

    The webdriver-active flag is set to true when the user agent is under remote control which is initially set to false.

    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.


    Update (6-Nov-2019)

    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:

    • Exclude the collection of enable-automation switches
    • Turn-off useAutomationExtension

    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/")
      

    Legends

    1: Applies to Selenium's Python clients only.

    2: Applies to Selenium's Python clients only.

    3: Applies to Selenium's Python clients only.

    0 讨论(0)
  • 2020-11-22 01:11

    I would like to add a Java alternative to the cdp command method mentioned by pguardiario

    Map<String, Object> params = new HashMap<String, Object>();
    params.put("source", "Object.defineProperty(navigator, 'webdriver', { get: () => undefined })");
    driver.executeCdpCommand("Page.addScriptToEvaluateOnNewDocument", params);
    

    In order for this to work you need to use the ChromiumDriver from the org.openqa.selenium.chromium.ChromiumDriver package. From what I can tell that package is not included in Selenium 3.141.59 so I used the Selenium 4 alpha.

    Also, the excludeSwitches/useAutomationExtension experimental options do not seem to work for me anymore with ChromeDriver 79 and Chrome 79.

    0 讨论(0)
  • 2020-11-22 01:12

    Finally this solved the problem for ChromeDriver, Chrome greater than 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);
    
    0 讨论(0)
  • 2020-11-22 01:17

    To exclude the collection of enable-automation switches as mentioned in the 6-Nov-2019 update of the top voted answer doesn't work anymore as of April 2020. Instead I was getting the following error:

    ERROR:broker_win.cc(55)] Error reading broker pipe: The pipe has been ended. (0x6D)
    

    Here's what's working as of 6th April 2020 with Chrome 80.

    Before (in the Chrome console window):

    > navigator.webdriver
    true
    

    Python example:

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

    After (in the Chrome console window):

    > navigator.webdriver
    undefined
    
    0 讨论(0)
  • 2020-11-22 01:17

    Nowadays you can accomplish this with cdp command:

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

    by the way, you want to return undefined, false is a dead giveaway.

    0 讨论(0)
  • 2020-11-22 01:24

    Do not use cdp command to change webdriver value as it will lead to inconsistency which later can be used to detect webdriver. Use the below code, this will remove any traces of webdriver.

    options.add_argument("--disable-blink-features")
    options.add_argument("--disable-blink-features=AutomationControlled")
    
    0 讨论(0)
提交回复
热议问题