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.

Breaking Out of the Chrome/WebExtension Sandbox

By Evan Sangaline
on September 14, 2018

A short guide to breaking out of the WebExtension content script sandbox.

Read more

Recreating Python's Slice Syntax in JavaScript Using ES6 Proxies

By Evan Sangaline
on June 28, 2018

A gentle introduction to JavaScript proxies where we use them to recreate Python's extended slice syntax.

Read more

Building a YouTube MP3 Downloader with Exodus, FFmpeg, and AWS Lambda

By Evan Sangaline
on May 21, 2018

A short guide to building a practical YouTube MP3 downloader bookmarklet using Amazon Lambda.

Read more

Comments