Locator Strategies (ID, CSS, XPath)
Every Selenium interaction starts with locating an element in the DOM, and the By class exposes eight strategies to do it: ID, NAME, CLASS_NAME, TAG_NAME, LINK_TEXT, PARTIAL_LINK_TEXT, CSS_SELECTOR, and XPATH. Selenium's official documentation recommends a rough priority order — prefer ID first, then CSS selectors, and reach for XPath only when you need something CSS genuinely cannot express, such as selecting an element by its visible text or walking upward to a parent.
Cricket analogy: Choosing among eight locator strategies is like a captain choosing among eight different field settings depending on the batter and situation — a slip cordon for a nervous new batter, a spread field for a set one — the right choice depends entirely on what you're actually trying to catch.
ID and Name Locators
By.ID is the fastest and most reliable locator because browsers index element IDs internally and, in valid HTML, an id attribute must be unique on the page — driver.find_element(By.ID, 'login-button') has no ambiguity to resolve. By.NAME works similarly for form elements carrying a name attribute, common on legacy forms and elements generated by server-side frameworks, but unlike id, name is not guaranteed unique, so it can silently return the first of several matching elements rather than the one you intended.
Cricket analogy: A unique ID being the fastest, most reliable locator is like identifying a player by their unique international cap number rather than by shirt name alone — no two players ever share a cap number, so there's zero ambiguity in who's being referenced.
CSS Selectors
CSS selectors combine tag names, classes, IDs, and attributes using the same syntax browsers use for styling: div.card, #username, input[type='submit'], and descendant/child combinators like nav > ul li a. They're generally faster than XPath in most browser engines and read naturally to anyone with front-end experience, which is why they're the default recommendation for anything beyond a simple unique ID. Attribute selectors are particularly useful for elements without stable IDs or classes: button[data-testid='checkout-submit'] targets a dedicated test attribute that, unlike CSS classes used for styling, is far less likely to change when a designer reworks the page's visual styling.
Cricket analogy: Using a data-testid attribute instead of a styling class is like identifying a fielder by their fixed squad number on the back of the shirt rather than by which colored bib they happen to be wearing in that day's training drill — the bib color changes with the drill, the squad number doesn't.
from selenium.webdriver.common.by import By
# ID - fastest, use whenever available
driver.find_element(By.ID, "login-button")
# CSS selector - attribute-based, resilient to styling changes
driver.find_element(By.CSS_SELECTOR, "button[data-testid='checkout-submit']")
# CSS - descendant combinator
driver.find_element(By.CSS_SELECTOR, "nav.main-nav > ul li a.active")
# XPath - select by visible text, which CSS cannot do
driver.find_element(By.XPATH, "//button[contains(text(), 'Add to Cart')]")
# XPath - traverse upward to a parent, which CSS also cannot do
driver.find_element(
By.XPATH, "//span[text()='Out of stock']/ancestor::div[@class='product-card']"
)Chrome DevTools lets you right-click any element in the Elements panel and choose Copy > Copy selector or Copy > Copy XPath, which is a fast way to get a starting locator — but the generated selector is often brittle (deeply nested, index-based) and should usually be hand-simplified before going into a real test suite.
XPath: When CSS Isn't Enough
XPath earns its place for two things CSS fundamentally cannot do: selecting by an element's text content, like //button[text()='Submit'] or the more forgiving //button[contains(text(), 'Submit')], and navigating the DOM in any direction, including upward to ancestors or sideways to siblings, using axes like ancestor::, following-sibling::, and parent::. CSS selectors can only ever select downward from a starting point — there is no CSS equivalent for 'find the div that contains this specific span,' which is exactly the kind of relationship XPath's ancestor axis expresses directly.
Cricket analogy: XPath's ability to select 'the parent card containing this specific text' is like a scorer being able to look up not just a specific delivery but the whole over it belongs to, working backward from a single ball to its containing context — a lookup a simple ball-by-ball list alone can't do.
Absolute, index-based XPaths copied straight from DevTools — like /html/body/div[3]/div/div[2]/section/div[5]/button — are extremely fragile. Adding or removing a single sibling div anywhere upstream shifts every index after it and silently breaks the locator. Prefer relative XPaths anchored on a stable attribute, like //div[@data-testid='cart-summary']//button, over absolute position-based paths.
- The By class supports eight locator strategies; ID and CSS selectors are generally preferred over XPath.
- By.ID is fastest and most reliable because IDs are (in valid HTML) unique per page.
- By.NAME is not guaranteed unique and can silently match the wrong element.
- CSS attribute selectors like [data-testid='...'] are more stable than selectors based on styling classes.
- XPath uniquely supports selecting by visible text and traversing upward via axes like ancestor::.
- CSS selectors can only select downward from a starting point, never upward to a parent.
- Absolute, index-based XPaths copied from DevTools are fragile and should be avoided in real test suites.
Practice what you learned
1. Why is By.ID generally the most reliable locator strategy?
2. What is a risk of using By.NAME as a locator?
3. What can XPath do that CSS selectors fundamentally cannot?
4. Why is a selector like button[data-testid='checkout-submit'] preferred over a class-based selector?
5. What is the main problem with an absolute, index-based XPath like /html/body/div[3]/div/div[2]/button?
Was this page helpful?
You May Also Like
Your First Selenium Script
A hands-on walkthrough of writing, running, and understanding a first Selenium WebDriver script in Python.
Selenium WebDriver Architecture
How Selenium WebDriver's client-server architecture routes commands from your test script to the browser using the W3C protocol.
What Is Selenium?
An introduction to Selenium, the open-source framework for automating web browsers, and why it's the backbone of web UI test automation.