How to Find Elements by CSS Selector in Selenium?

CSS selectors allow you to target DOM elements on a web page in a CSS-like syntax. They are one of the most useful and commonly used tools for parsing HTML and interacting with web pages in Selenium. In this comprehensive guide, you'll learn:

  • What are CSS selectors and why are they useful?
  • Supported CSS selector syntax in Selenium
  • Finding elements by CSS selector with find_element() and find_elements()
  • Targeting elements by ID, class, attribute, hierarchy, and more
  • Advanced selector techniques like pseudo-classes and combinators
  • Tips for writing reliable and readable CSS selector queries
  • Common examples and use cases for CSS selectors in Selenium

What Are CSS Selectors?

CSS selectors allow developers to target DOM elements by matching against element names, IDs, classes, attributes, and more. They were originally designed for styling documents with CSS, but are now commonly used for web scraping and browser automation.

For example, the CSS selector p will match all paragraph elements on a page. The selector #header will match the element with id=”header”. Compared to other element selection mechanisms like XPath, CSS selectors tend to be faster, more concise, and easier to read/maintain. Their syntax is also familiar to anyone with CSS experience.

Why Use CSS Selectors in Selenium?

Here are some key advantages of using CSS selectors in Selenium:

  • More concise syntax: CSS selector queries tend to be shorter and simpler compared to XPath. For example, document.querySelectorAll('p.important') vs //p[contains(@class, 'important')].
  • Readability: CSS selectors read closer to natural language, making them easier to understand and maintain.
  • Speed: Browsers can evaluate CSS selectors faster than XPath in most cases.
  • Power and flexibility: CSS selectors are highly expressive, supporting selection by ID/class/attribute/hierarchy/content and more.
  • W3C standard: CSS selector syntax is standardized and consistent across all major browsers.

Overall, CSS selectors strike a great balance between brevity, readability, speed, and flexibility compared to other element selection mechanisms. They are one of the most fundamental tools for interacting with DOM elements in browser automation.

Supported CSS Selector Syntax

Selenium supports most standard CSS selector syntax defined in the Selectors Level 3 spec. This includes:

  • Simple selectors – target by element type, ID, class, attribute, state, etc.
  • Combinators – combine simple selectors to target hierarchy and relationships.
  • Pseudo-classes – select by element state (:hover:focus etc).
  • Pseudo-elements – select a part of an element (:before:first-line etc).
  • Selector lists – combine multiple selectors into one query.

There are some limitations compared to native browser support:

  • No support for newer Level 4 selectors like :is() or :where().
  • Partial support for general siblings (~) and column (||) combinators.
  • No support for custom pseudo-classes/elements or vendor prefixes.

But overall, Selenium supports the majority of standard CSS selector features you would expect.

Finding Elements with find_element() and find_elements()

Selenium provides two main methods for finding elements using CSS selectors:

find_element(By.CSS_SELECTOR, 'selector')

  • Finds single matching element.
  • Throws NoSuchElementException if no match.
element = driver.find_element(By.CSS_SELECTOR, 'p.important')

find_elements(By.CSS_SELECTOR, 'selector')

  • Finds all matching elements.
  • Returns empty list if no match.
elements = driver.find_elements(By.CSS_SELECTOR, 'p.important')

We import By to reference the selection mechanism, and pass the selector query as a string.

These methods allow us to efficiently find elements by CSS selector in Selenium for web scraping or automation.

Targeting by Element Type

The most basic CSS selector matches by element type or tag name:

elementname {
  /* Styles */ 

For example, to find all <p> elements:

paragraphs = driver.find_elements(By.CSS_SELECTOR, 'p')

This selects all paragraphs on the page. We can target any valid HTML tag like div, table, a, form, etc.

Targeting by ID

To select an element by unique ID, we use the #id syntax:

#uniqueid {
  /* Styles */

For example:

header = driver.find_element(By.CSS_SELECTOR, '#pageHeader')

This will find the element with id="pageHeader". ID selectors are very useful for singular elements like page headers, navigation, etc.

Targeting by Class

To find elements by class name, we use the .classname selector:

.bluebanner {
  /* Styles */

For example:

banners = driver.find_elements(By.CSS_SELECTOR, '.promo')

This will find all elements with class="promo".

Class selectors are useful for broader categories of elements like promotions, notifications, etc.

Targeting by Attribute

CSS selectors can also match elements by attribute or attribute value:

[attrname] {
  /* Has attribute */

[attrname=value] {
  /* Attribute equals value */ 

[attrname^=value] {
  /* Attribute starts with value */

[attrname$=value] {
  /* Attribute ends with value */

[attrname*=value] {
  /* Attribute contains value */

For example:

# Images with title attribute
images = driver.find_elements(By.CSS_SELECTOR, 'img[title]')

# Images with title attribute = "hero" 
hero_images = driver.find_elements(By.CSS_SELECTOR, 'img[title="hero"]')

# Links starting with "https://"
external_links = driver.find_elements(By.CSS_SELECTOR, 'a[href^="https://"]')

This allows selection of elements with specific attributes or values.

Combining Selectors

Simple selectors can be combined to target elements based on multiple criteria:

By Class and Type

p.important {
  /* Styles */

Find important paragraphs:

paras = driver.find_elements(By.CSS_SELECTOR, 'p.important')

By ID and Class

#header.clearfix {
  /* Styles */  

Select header with clearfix class:

header = driver.find_element(By.CSS_SELECTOR, '#header.clearfix')

By Attribute and Type

div[data-test="abc"] {
  /* Styles */

Select div with attribute data-test="abc":

div = driver.find_element(By.CSS_SELECTOR, 'div[data-test="abc"]')

Targeting DOM Hierarchy

CSS Selector combinators allow us to target elements based on their hierarchy and relationship to other elements.

Descendant Combinator

The whitespace combinator matches elements descended from parent elements:

ancestor descendant {
  /* Styles */

For example:

# Paragraphs inside div.content 
paras = driver.find_elements(By.CSS_SELECTOR, 'div.content p')

This finds <p> tags anywhere under <div class="content">.

Child Combinator

The > child combinator selects direct children of elements:

parent > child {
  /* Styles */

For example:

# Direct li children of  
items = driver.find_elements(By.CSS_SELECTOR, ' > li')

This finds <li> tags directly inside <ul class="menu">, not all descendants.

Adjacent Sibling Combinator

The + adjacent sibling combinator selects the first element immediately following another:

element + nextSibling {
  /* Styles */

For example:

# h2 after each h1 
subheaders = driver.find_elements(By.CSS_SELECTOR, 'h1 + h2')

This finds <h2> tags directly following <h1>, not other elements in between.

General Sibling Combinator

The ~ general sibling combinator selects any sibling elements following another:

element ~ siblings {
  /* Styles */ 

For example:

# All h2 tags following h1
subheaders = driver.find_elements(By.CSS_SELECTOR, 'h1 ~ h2')

This finds <h2> tags following <h1> tags, even if other elements exist in between.

Note: General sibling selectors have partial support in Selenium depending on browser version.

Combinators let us target elements based on their position and hierarchy in the DOM tree.


CSS pseudo-classes select elements by state or position rather than direct attributes:

selector:pseudo-class {
  /* Styles */

Some useful pseudo-classes include:

  • :first-child – first child element.
  • :last-child – last child element.
  • :nth-child(n) – match nth child.
  • :first-of-type – first sibling of type.
  • :last-of-type – last sibling of type.
  • :nth-of-type(n) – nth sibling of type.
  • :not(selector) – elements that do not match the selector.

For example:

# First paragraph
first_para = driver.find_element(By.CSS_SELECTOR, 'p:first-child')

# Last menu item
last_item = driver.find_element(By.CSS_SELECTOR, 'ul > li:last-child')  

# Every 3rd item
items = driver.find_elements(By.CSS_SELECTOR, 'ul > li:nth-child(3n)')

# Exclude paragraphs    
content = driver.find_elements(By.CSS_SELECTOR, 'div :not(p)')

This allows the selection of elements based on positional relationships rather than direct attributes. Other pseudo-classes like :hover, :focus, :active etc. can identify the element state.


CSS pseudo-elements target specific parts of elements:

element::pseudo-element {
  /* Styles */

For example:

p::first-line {
  /* Styles for first line of each <p> */

p::first-letter {
  /* Styles for first letter of each <p> */  

p::before {
  /* Generate content before each <p> */

p::after {
  /* Generate content after each <p> */

Some common pseudo-elements:

  • ::first-line – first line of text in element.
  • ::first-letter – first letter of text in element.
  • ::before – insert content before element.
  • ::after – insert content after element.

Note that pseudo-elements can be used for styling, but not for selecting existing page elements in Selenium.

Selector Lists

Multiple selectors can be combined by separating them with commas:

selector1, selector2, selector3 {
  /* Shared styles */

This matches any element that matches one or more of the selectors.

For example:

headers = driver.find_elements(By.CSS_SELECTOR, 'h1, h2, h3, h4, h5, h6')

This finds all header elements <h1> through <h6>.

Tips for Writing Effective CSS Selectors

Here are some tips for writing optimized CSS selector queries:

  • Prefer ID and class selectors for fastest performance. Match by direct ID or class whenever possible.
  • Avoid overqualified selectors like body #container .content p – These are more brittle and slower than p alone.
  • Combine selectors gracefully – Strike a balance between concise and unambiguously descriptive.
  • Test selectors in the browser console to ensure they match expected elements.
  • Read selector specificity docs to understand precedence rules when combining selectors.
  • Leverage selectors lists for cleaner queries matching multiple selectors.
  • Use unique attributes like data-test-id when IDs/classes are dynamic or non-semantic.

The following selector best practices help write queries that are performant, robust, and maintainable.

Common Use Cases and Examples

Some common examples of using CSS selectors in Selenium:

# By ID
user_menu = driver.find_element(By.CSS_SELECTOR, '#user-menu') 

# By class 
notifications = driver.find_elements(By.CSS_SELECTOR, '.notification')

# By attribute
submit_btn = driver.find_element(By.CSS_SELECTOR, 'button[type="submit"]')

# Descendant 
email_link = driver.find_element(By.CSS_SELECTOR, '.account-info a')

# Direct child 
featured_product = driver.find_element(By.CSS_SELECTOR, '.products > .featured')

# Pseudo-class
first_result = driver.find_element(By.CSS_SELECTOR, 'div.results li:first-child') 

# Selector list
titles = driver.find_elements(By.CSS_SELECTOR, 'h1, h2, h3')

CSS selectors are the go-to tool for most element selection tasks in Selenium, from navigation to forms to listings and more.


CSS selectors are ideal for most element selection tasks in Selenium. With the power of CSS selectors, you can effectively target elements for automated testing and browser automation scripts. They provide an indispensable tool for parsing and analyzing web documents and applications using Selenium.

John Rooney

John Rooney

John Watson Rooney, a self-taught Python developer and content creator with a focus on web scraping, APIs, and automation. I love sharing my knowledge and expertise through my YouTube channel, My channel caters to all levels of developers, from beginners looking to get started in web scraping to experienced programmers seeking to advance their skills with modern techniques. I have worked in the e-commerce sector for many years, gaining extensive real-world experience in data handling, API integrations, and project management. I am passionate about teaching others and simplifying complex concepts to make them more accessible to a wider audience. In addition to my YouTube channel, I also maintain a personal website where I share my coding projects and other related content.

We will be happy to hear your thoughts

      Leave a reply

      Compare items
      • Total (0)