Using Google Chrome Extensions with Selenium

By Evan Sangaline | November 20, 2017

Running Google Chrome with an extension installed is quite simple because Chrome supports a --load-extension command-line argument for exactly this purpose. This can be specified before launching Chrome with Selenium by creating a ChromeOptions instance and calling add_argument().

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException


# Configure the necessary command-line option.
options = webdriver.ChromeOptions()
options.add_argument('--load-extension=path/to/the/extension')

# Initalize the driver with the appropriate options.
driver = webdriver.Chrome(chrome_options=options)

The above code will setup a Selenium driver for Chrome with the extension located at path/to/extension preinstalled.

Let’s make a very minimal Chrome extension and use it to verify that this code works. We’ll first need to make a directory to hold the extension

mkdir chrome-extension

and then we’ll need to create a manifest.json file inside of that directory to define the basic meta-information for the extension. Here’s a very basic example of a manifest.json file

{
  "manifest_version": 2,
  "name": "Chrome Extensions With Selenium",
  "version": "1.0.0",
  "content_scripts": [
    {
      "matches": ["*://*/*"],
      "js": ["content.js"],
      "run_at": "document_start"
    }
  ]
}

which includes only the minimum required fields and one content script. The content script is expected to be located in chrome-extension/content.js and it will be automatically injected into every page when the extension is installed. You can put whatever you want in here for web scraping or browser automation purposes, but here’s a useful piece of code for testing that Chrome is successfully loading the extension before launching.

// Wait for the DOM to completely load.
document.addEventListener("DOMContentLoaded", () => {
  // Overwrite the contents of the body.
  document.body.innerHTML = '<h1 id="installed" >Successfully Installed!</h1>';
});

This code will first wait for the DOM to load completely and will then replace the entire body of the document with a big banner saying “Successfully Installed!” We can write a simple test script for this that checks for the injected h1 tag and prints out a success or failure message.

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException


# Configure the necessary command-line option.
options = webdriver.ChromeOptions()
# Note that `chrome-extension` is the path to the unpackaged extension.
options.add_argument('--load-extension=chrome-extension')

# Navigate to any page... well, not just *any* page...
driver = webdriver.Chrome(chrome_options=options)
driver.get('https://intoli.com')

# Check if the extension worked and log the result.
try:
    header = driver.find_element_by_id('successfully-installed')
    print('Success! :-)')
except NoSuchElementException:
    print('Failure! :-(')
finally:
    # Clean up.
    driver.quit()

Running the script should output

Success! :-)

provided that everything is working correctly. The browser will quit automatically during the test, but you’ll like also see our success message flash briefly on the screen before that happens.

Successfully Installed!

Note that if you attempt to run this test in headless mode by adding an options.add_argument('--headless') line, you will unfortunately see the failure message.

Failure! :-(

This is because Google Chrome currently does not support Extensions in headless mode. If you have a use case for Chrome in headless mode then be sure to let the Chrome team know! It’s something that many of us would really love to see, and it will only happen if they get significant feedback about the issue.

Suggested Articles

If you enjoyed this article, then you might also enjoy these related ones.

What's New in Exodus 2.0

By Evan Sangaline
on March 8, 2018

A tour of the new features introduced in Exodus version 2.0.

Read more

Extending CircleCI's API with a Custom Microservice on AWS Lambda

By Evan Sangaline
on February 20, 2018

A guide to setting up a practical proxy API on Amazon's Lambda using Node.js and Express.

Read more

It is *not* possible to detect and block Chrome headless

By Evan Sangaline
on January 18, 2018

An updated example of techniques to avoid detection.

Read more

Comments