Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Use Selenium’s plural lookup and test the returned list: driver.find_elements(By.CSS_SELECTOR, "#target") is truthy when at least one matching node exists and false when the list is empty. This is the cleanest immediate existence check because it does not require catching an exception.
That check describes the DOM at one instant. For JavaScript-rendered content, use an explicit wait for presence (or visibility when that is what your test needs) before branching or interacting.
The immediate existence check
Import By, locate all matching nodes, and let Python evaluate the collection’s truthiness:
from selenium.webdriver.common.by import By
matches = driver.find_elements(By.CSS_SELECTOR, "#target")
if matches:
print("Element exists in the current DOM")
else:
print("No matching element was found")
find_elements returns a collection of matching WebElement objects. If nothing matches, Selenium returns an empty list, which Python treats as false. If one or more nodes match, the list is true. The test therefore answers “does at least one node matching this locator exist right now?” without exception handling.
#1 Best Overall
Check how many elements matched
When uniqueness matters, inspect the length instead of only using truthiness:
matches = driver.find_elements(By.ID, "target")
if len(matches) == 0:
print("Missing")
elif len(matches) == 1:
print("Exactly one match")
else:
print(f"Unexpectedly found {len(matches)} matches")
A true result alone does not prove that the locator is unique. A broad CSS selector can match several nodes, including hidden duplicates or repeated components.
When to use find_element instead
Use the singular method when your next operation needs one expected element. Selenium returns the first matching WebElement. If no element matches, the lookup raises NoSuchElementException.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By
try:
element = driver.find_element(By.ID, "target")
except NoSuchElementException:
element = None
if element is not None:
print("Found the first matching element")
# element.click(), element.text, or another operation can follow
else:
print("The expected element is absent")
This form is useful when absence is exceptional for the test or when you immediately need the returned object. For a simple optional branch, find_elements is usually clearer because “none found” is represented by an empty collection rather than an exception.
Do not hide real failures with a broad exception
Catch NoSuchElementException for the singular lookup. Avoid catching every exception around the lookup: a malformed locator, a browser problem, or a later interaction failure is a different defect and should remain visible.
Rank #2
Choose a locator that identifies the intended node
The Python API supports ID, name, XPath, CSS selector, class name, tag name, link text, and partial link text strategies. Pick the most stable attribute available in the page under test.
| Need | Pattern | What it establishes |
|---|---|---|
| Branch on whether a match exists now | bool(driver.find_elements(By.ID, "target")) |
At least one node matched at lookup time, or none did. |
| Retrieve one expected match | driver.find_element(By.ID, "target") |
The first matching WebElement; no match raises NoSuchElementException. |
| Use a CSS selector | driver.find_elements(By.CSS_SELECTOR, "form#login input[name='email']") |
All nodes matching the selector in the current search context. |
| Search inside an existing element | card.find_elements(By.CLASS_NAME, "price") |
Matches within that WebElement, rather than the whole document. |
A locator can be syntactically valid yet point at the wrong node. If the check unexpectedly returns zero or many matches, inspect the selector and the current page state before changing the wait.
Handle elements that appear after navigation or interaction
A one-time lookup reports only the state at the moment it runs. If application JavaScript adds the element later, wait on a condition instead of guessing with a fixed sleep.
Wait for DOM presence
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
locator = (By.CSS_SELECTOR, "#target")
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located(locator)
)
print("A matching node is now present:", element)
presence_of_element_located waits until a matching element is present in the DOM and returns the WebElement. WebDriverWait.until keeps polling until the condition is truthy. If the timeout expires, Selenium raises TimeoutException.
The documented default polling interval is 0.5 seconds, and the wait’s default ignored exception is NoSuchElementException. The example’s 10-second timeout is a bounded choice; set it to the maximum delay your application legitimately needs rather than waiting indefinitely.
Rank #3
Convert a wait timeout into an existence result
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
locator = (By.ID, "target")
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located(locator)
)
except TimeoutException:
element = None
if element is None:
print("The element did not become present within 10 seconds")
else:
print("The element exists in the DOM")
This pattern is appropriate when absence after the deadline is an expected branch. If the element is mandatory, allow the timeout to fail the test so the failure is reported instead of silently converted into a pass.
Recommended Free Tools
Presence is not visibility
Presence means that Selenium found a node in the DOM. It does not necessarily mean that the node is visible. A hidden menu item, an off-screen component, or an element with no rendered size can satisfy a presence condition.
Wait until Selenium considers it visible
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
locator = (By.CSS_SELECTOR, "#target")
visible_element = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located(locator)
)
visible_element.click()
Selenium’s visibility condition requires the element to be displayed and to have nonzero height and width. Use it when the test’s requirement is “the user can see this,” not merely “the node has been inserted.” Even a visible element may still be unsuitable for a particular action, so keep action-specific checks separate.
Pick the condition that matches the assertion
- DOM existence: use
find_elementsfor an immediate snapshot orpresence_of_element_locatedfor a bounded wait. - Rendered visibility: use
visibility_of_element_located. - Optional content: use a plural lookup and branch on whether the list is empty.
- Required content: use a wait and let
TimeoutExceptionidentify a failed expectation.
Implicit and explicit waits
Selenium provides both implicit and explicit wait mechanisms. For a particular event such as presence or visibility, a bounded explicit wait states exactly what the test is waiting for and keeps the timeout next to the assertion.
Do not rely on an assumed formula for combining implicit and explicit waits. The effective interaction can depend on the installed Selenium version and the individual calls. If a project uses both mechanisms, consult the waits documentation for that version and keep timing behavior consistent across the suite.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesRank #4
Reusable helper functions
Immediate check
from selenium.webdriver.common.by import By
def element_exists(driver, locator):
"""Return True when locator matches at least one current DOM node."""
return bool(driver.find_elements(*locator))
if element_exists(driver, (By.CSS_SELECTOR, "#target")):
print("Present now")
Waited check with an explicit deadline
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def element_appears(driver, locator, timeout=10):
try:
WebDriverWait(driver, timeout).until(
EC.presence_of_element_located(locator)
)
return True
except TimeoutException:
return False
if element_appears(driver, ("css selector", "#target"), timeout=10):
print("Appeared before the deadline")
Passing a locator tuple keeps the selector strategy and value together. In normal code, use the named By constants, for example (By.CSS_SELECTOR, "#target"); the string form in the final example is equivalent to Selenium’s CSS strategy.
Or skip the browser setup
If your goal is a visual record of a page rather than a DOM assertion, ScreenshotNeo provides a single-request website screenshot API. It accepts consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Only clean shots are billed, while bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.
For API details, see the ScreenshotNeo documentation. A complete cURL request is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo also has an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it.
Free tools Windows power users keep installed
One-click scans. No signup required.
Equivalent calls from Python and Node.js
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
These calls capture a rendered image; they do not replace Selenium when you need to inspect a locator, wait for a state, or assert against the DOM.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshooting existence checks
The check returns an empty list, but the page appears to contain the element
- Timing: the lookup ran before JavaScript inserted the node. Replace the one-time call with
WebDriverWait(...).until(EC.presence_of_element_located(...)). - Locator mismatch: verify the ID, class, tag, link text, XPath, or CSS selector and check for spelling and quoting errors.
- Wrong search context: a lookup from a
WebElementsearches only that element’s descendants. Search fromdriverwhen the target is elsewhere, or from the correct container when scoping is intentional.
The presence wait succeeds, but clicking or reading it fails
Presence proves DOM insertion, not visibility or action readiness. Use visibility_of_element_located when the requirement is display, then apply the checks required by the specific action.
Best Value
The singular lookup raises NoSuchElementException
That is Selenium’s documented result when find_element has no match. Use the plural lookup for an ordinary optional branch, or add a bounded explicit wait when the element is expected to arrive asynchronously.
The explicit wait raises TimeoutException
At least one poll completed without satisfying the condition before the deadline. Check the locator and page state first; increase the timeout only when the application’s legitimate load time requires it. If the element is optional, catch the timeout and return a false result as shown above.
A previously stored element no longer behaves reliably
Dynamic pages can replace nodes after you locate them. Locate again when the page updates, and use a condition against the current locator rather than assuming an earlier reference remains attached forever.
Version and documentation note
The Python WebDriver and finder pages reviewed for this guidance are displayed as Selenium 4.49.0 documentation, while the expected-conditions page is displayed as Selenium 4.33.0. Those displayed versions are not a promise that every installed package has identical signatures. Check the documentation corresponding to the Selenium version installed in your project before depending on version-specific behavior.
A practical decision sequence
- Define what “exists” means for the test: a node in the DOM, a visible element, or an element ready for a particular action.
- Choose a stable locator and decide whether multiple matches are acceptable.
- For a current snapshot, call
find_elementsand test the list. - For one required element, call
find_elementor wait for a condition that returns it. - For late-loading content, use a bounded explicit wait instead of a fixed sleep.
- When a wait fails, inspect timing, locator, and search context before changing the assertion.
Frequently Asked Questions
Does a true find_elements result guarantee that the locator is unique?
No. It guarantees only one or more matches. Compare len(matches) with 1 when the test requires exactly one node.
What does Selenium return when a plural lookup finds nothing?
An empty collection (an empty Python list), which evaluates to False in a conditional.
Which Selenium documentation version should I follow?
Match the documentation to the package installed in your project. The finder and WebDriver pages surfaced as 4.49.0, while the expected-conditions page surfaced as 4.33.0, so verify version-specific details locally.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

