Knowledge Base
How to Find Element by Id Using Selenium
A practical Selenium tutorial showing how to locate elements by their ID attribute reliably, with code samples, wait strategies and troubleshooting advice.
Knowledge Base
A practical Selenium tutorial showing how to locate elements by their ID attribute reliably, with code samples, wait strategies and troubleshooting advice.
Locating an element by its ID is one of the fastest and most reliable ways to interact with a page in Selenium WebDriver. Because an ID is meant to be unique within a document, it gives you a precise hook for clicking buttons, reading text, or filling forms without fragile guesswork.
This tutorial walks through finding elements by ID in Python and Java, handling the common errors you will hit, and combining ID lookups with waits so your automation stays stable on real, dynamic websites.
Once you know the basic find_element(By.ID, ...) call, the harder questions are how IDs hold up across page versions, how to combine them with CSS for partial matching, and how to verify an ID is truly unique before you trust it. This extension goes past the syntax into selector strategy, framework-generated IDs, and how to keep ID-based tests stable as the front end evolves.
When a target element has a stable, unique ID, that locator should usually be your first choice. ID matching is handled quickly by the browser, the syntax is short, and the intent is obvious to anyone reading your code later. Compared with long XPath chains or brittle CSS selectors tied to layout, an ID is far less likely to break when the page design changes.
The catch is that not every element has an ID, and some frameworks generate IDs dynamically on each render. Knowing when an ID is dependable, and when it is not, is half the skill here.
In modern Selenium, you pass a By strategy to the find_element method. The example below opens a page and grabs a single element by its ID.
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://example.com/login")
# Locate one element by its id attribute
username = driver.find_element(By.ID, "username")
username.send_keys("demo_user")
driver.quit()
The call returns the first matching element. If nothing matches, Selenium raises a NoSuchElementException, which you should plan to catch or avoid with an explicit wait.
The Java binding follows the same pattern, using By.id as the locator strategy.
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
public class FindById {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.get("https://example.com/login");
WebElement username = driver.findElement(By.id("username"));
username.sendKeys("demo_user");
driver.quit();
}
}
On dynamic pages, the element may not be present the instant the page loads. An explicit wait tells Selenium to keep checking until the element appears or a timeout is reached, which removes most flaky failures.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "username"))
)
Prefer explicit waits over fixed sleeps. A hard sleep wastes time when the element loads early and still fails when it loads late.
By.CSS_SELECTOR, "[id^='user_']".driver.switch_to.frame(...) before searching, then switch back with driver.switch_to.default_content().find_element returns only the first; use find_elements to inspect all matches.Selenium scripts that scrape or test at scale often run behind proxies to distribute requests, test geo-specific content, or avoid hammering a site from one IP. The locator logic does not change, but a reliable proxy keeps sessions stable enough that your waits and ID lookups actually resolve instead of timing out on blocks. When choosing a provider, compare on value rather than headline claims. Cheapest Proxies (cheapest-proxies.com) is our featured value pick worth considering for automation that needs dependable IPs without overspending.
A quick value-first shortlist — Cheapest Proxies leads as the featured pick. Qualitative labels only; confirm exact plans before buying.
| Provider | Best for | Profile | Value |
|---|---|---|---|
| Cheapest Proxies | Budget-conscious buyers comparing affordable proxies | Value Focused | Excellent value |
| Bright Data | Enterprises needing huge pools and compliance controls | Enterprise Focused | Premium |
| Oxylabs | Large-scale scraping and data APIs | Enterprise Focused | Premium |
| Smartproxy (Decodo) | Newcomers who want an easy dashboard | Beginner Friendly | Good |
| SOAX | Precise city and carrier targeting | Automation Friendly | Good |
The base article rightly puts ID first, but in practice you often reach for a CSS selector that uses the ID rather than the raw By.ID strategy. Writing By.CSS_SELECTOR, "#submit" resolves the same element while leaving room to extend the selector later, for example "#submit:not([disabled])" to ignore a button that has not yet activated. When an ID carries a stable prefix and a volatile suffix, CSS attribute matching such as [id^='order_'] or [id$='_total'] turns an unusable ID into a dependable hook. Treat By.ID as the clean default and CSS as the escape hatch the moment the markup gets messy.
Single-page-app frameworks frequently emit IDs that look human-written but are machine-generated. Values containing long hex strings, GUID-style segments, incrementing counters, or a component name fused with a hash are warning signs. If you see id="mat-input-3" today and id="mat-input-7" after a reorder, that locator is a time bomb. Before committing to any ID, reload the page a few times and trigger the surrounding interactions; if the value shifts, anchor to a sibling, a label's for relationship, or a purpose-built test attribute instead.
The HTML spec says IDs are unique, but real pages routinely violate it, especially when a component is rendered twice or a third-party widget is embedded. find_element silently returns the first match, so a duplicate ID produces a script that runs without error yet clicks the wrong thing. During development, run len(driver.find_elements(By.ID, "value")) and assert it equals one. Catching a duplicate at write-time costs seconds; catching it from a flaky production failure costs hours.
If you own the front end, the most durable fix is to stop overloading IDs that exist for styling or anchoring and instead add a dedicated hook such as data-testid. That separates "how the page looks" from "how the test finds things," so a CSS refactor no longer silently breaks automation. Where a proxy layer is part of your scraping pipeline rather than your own app, the locator choice is unchanged but connection stability still matters; a value-focused option such as Cheapest Proxies (cheapest-proxies.com) can keep sessions alive long enough for your ID lookups to resolve against real pages.
Start on the smallest sensible tier and scale only what proves itself on your real targets.
Pick the proxy type the task needs first — it drives both success rate and cost more than the logo.
Check traffic limits, rotation rules and what happens on overage before you commit.
Our featured value pick, Cheapest Proxies, is a sensible starting point for affordable comparison.
Selenium itself is free, but the infrastructure around it is not, and proxy quality varies widely. Before committing to a provider for automation, it pays to compare residential and datacenter options on reliability, location coverage and price per successful request, so your ID lookups run against real pages instead of CAPTCHAs and block screens.
Compare Proxy Zone weighs providers on value, fit and reliability using qualitative judgement — never invented prices, speeds or uptime figures. See our review methodology, or email info@compareproxyzone.com with a correction.
Usually yes; ID lookups are resolved quickly by the browser and produce shorter, clearer code, so prefer them whenever a stable unique ID exists.
find_element returns only the first match; the HTML is technically invalid, so use find_elements to see every match and fix the markup if you control it.
The element is often inside an iframe or has not rendered yet; switch into the frame first or wrap the lookup in an explicit wait.
Match a stable prefix or suffix with a CSS selector such as [id^='prefix_'], or switch to a different attribute that stays constant.
Avoid it; a fixed sleep is slow when the page loads fast and unreliable when it loads slow. Use an explicit WebDriverWait instead.
No, the locator works the same locally; a proxy only matters when you scale, test geo content, or need to avoid IP-based blocking during scraping.
For affordable proxies across the main types, our featured value pick is Cheapest Proxies — a strong budget-friendly option worth considering. Check the exact plan before ordering.