Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use Selenium’s plural finder, then read the item at zero-based index 1. In Python, the direct solution is:

from selenium.webdriver.common.by import By

matches = driver.find_elements(By.CLASS_NAME, "item")
second = matches[1]

find_element (singular) always returns the first matching element. find_elements returns every match, so it is the method you need when selecting the second, third, or another occurrence. Selenium documents this behavior in its element-finder guide.

The basic pattern

Assume the page contains several elements such as <div class="item">. Selenium’s result list is zero-based: the first element is index 0, and the second is index 1.

from selenium.webdriver.common.by import By

matches = driver.find_elements(By.CLASS_NAME, "item")
if len(matches) > 1:
    second = matches[1]
    second.click()

If fewer than two elements match, indexing at [1] raises Python’s IndexError. The length check makes the failure explicit and lets you choose a fallback.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What singular and plural finders return

  • driver.find_element(...) returns a reference to the first match.
  • driver.find_elements(...) returns a list containing all matches.
  • If no elements match, the plural method returns an empty list; the singular method raises NoSuchElementException.

These behaviors are described by the Selenium Project’s Finding web elements documentation.

Use the correct locator

A single class token

By.CLASS_NAME expects one class token, without a leading dot and without spaces:

matches = driver.find_elements(By.CLASS_NAME, "item")
second = matches[1]

For the HTML <article class="item featured">, use "item" or "featured" separately. Do not pass "item featured" to By.CLASS_NAME; a space-separated value is not one class name.

Two or more class tokens with CSS

When the target must have both item and active, use a CSS selector. Each class token gets a dot:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
matches = driver.find_elements(By.CSS_SELECTOR, ".item.active")
if len(matches) > 1:
    second = matches[1]

CSS selectors also let you narrow by an attribute, element type, or relationship:

# second matching button with both classes
buttons = driver.find_elements(By.CSS_SELECTOR, "button.item.active")
second_button = buttons[1]

# items with a data attribute
cards = driver.find_elements(By.CSS_SELECTOR, ".item[data-state='ready']")
second_ready = cards[1]

Selenium’s locator strategies explain class-name and CSS-selector usage. The Java API also notes that className is for one class and that multiple classes should be matched with cssSelector (see the Java By API).

Complete Python example

This runnable example opens a page, waits for at least two matching elements, and clicks the second one. Replace the URL and selector with your own page.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException

options = webdriver.ChromeOptions()
# options.add_argument("--headless=new")  # enable for a headless run
driver = webdriver.Chrome(options=options)

try:
    driver.get("https://example.com/products")

    def at_least_two(d):
        elements = d.find_elements(By.CLASS_NAME, "item")
        return elements if len(elements) >= 2 else False

    try:
        items = WebDriverWait(driver, 15).until(at_least_two)
    except TimeoutException:
        raise RuntimeError("The page did not contain two elements with class 'item' within 15 seconds")

    second = items[1]
    print(second.text)
    second.click()
finally:
    driver.quit()

The custom wait is useful for pages that add cards after an AJAX request. A normal presence wait only guarantees one element, so it does not by itself prove that index 1 exists.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Java equivalent

Java’s List is also zero-based. Selenium’s Java method is findElements, and the class-name locator is By.className:

import java.time.Duration;
import java.util.List;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;

WebDriver driver = new ChromeDriver();
try {
    driver.get("https://example.com/products");

    WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15));
    List<WebElement> items = wait.until(d -> {
        List<WebElement> found = d.findElements(By.className("item"));
        return found.size() >= 2 ? found : null;
    });

    WebElement second = items.get(1);
    second.click();
} finally {
    driver.quit();
}

If the list has fewer than two entries, get(1) throws IndexOutOfBoundsException; check items.size() > 1 when the second item is optional.

Search inside a specific container

A page may contain unrelated elements with the same class in a navigation bar, sidebar, and main content. First locate the intended parent, then call the plural finder on that element. This prevents matches outside the component from changing which element is “second.”

panel = driver.find_element(By.ID, "results-panel")
items = panel.find_elements(By.CLASS_NAME, "item")
if len(items) > 1:
    second = items[1]

The same pattern works with CSS:

panel = driver.find_element(By.CSS_SELECTOR, "section.results")
second = panel.find_elements(By.CSS_SELECTOR, ".item.active")[1]

Wait for the right state before indexing

Element order is the order returned in the current DOM, normally corresponding to document order. It can change when a page sorts, filters, paginates, virtualizes, or prepends content. Decide what “second” means for your test:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Second currently rendered match: call find_elements immediately before interacting.
  • Second after loading: wait until at least two are present.
  • Second with a property: include that property in the selector instead of relying on a broad class.
  • Second visible match: filter the returned elements with is_displayed(), understanding that visibility can change between the check and the click.
visible = [e for e in driver.find_elements(By.CLASS_NAME, "item")
           if e.is_displayed()]
if len(visible) > 1:
    visible[1].click()

For a stable test, prefer a semantic attribute such as data-testid or a unique descendant over a positional assumption when the application provides one.

XPath alternatives

CSS is usually the clearest option, but XPath can express positional selection directly:

# second element in document order among elements with class token item
second = driver.find_element(
    By.XPATH,
    "(//*[contains(concat(' ', normalize-space(@class), ' '), ' item ')])[2]"
)

The parentheses are important: they apply the position to the complete match set. A simpler XPath such as //*[@class='item'][2] only matches an exact class attribute and misses elements that have additional classes. For multiple class tokens:

second = driver.find_element(
    By.XPATH,
    "(//*[contains(concat(' ', normalize-space(@class), ' '), ' item ')][contains(concat(' ', normalize-space(@class), ' '), ' active ')])[2]"
)

Using find_elements and indexing in your programming language is often easier to read and lets you handle an absent second match without an exception from the locator itself.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Common errors and fixes

Only the first element is returned

Cause: the code uses find_element. Fix: switch to find_elements and select index 1.

IndexError or IndexOutOfBoundsException

Cause: fewer than two elements matched at the time of lookup. Fix: check the collection length, wait for the required count, or correct the selector.

Invalid selector or no matches with multiple classes

Cause: a space-separated string was passed to By.CLASS_NAME. Fix: use one token with By.CLASS_NAME, or use By.CSS_SELECTOR, ".first.second".

The test clicks the wrong “second” item

Cause: the selector spans multiple containers, hidden templates, ads, or dynamically reordered content. Fix: scope the search to a parent, require visibility or state in the selector, and inspect the returned elements’ text and attributes.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

StaleElementReferenceException

Cause: the framework re-rendered the list after you collected the elements. Fix: wait for the update to finish, locate the collection again immediately before the action, and avoid retaining old element references across a refresh.

The element exists but cannot be clicked

Cause: it is covered, outside the viewport, disabled, or not yet interactable. Fix: wait for clickability, scroll it into view, verify it is enabled, and investigate overlays rather than relying on JavaScript clicks that can hide real user-flow defects.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance and maintainability

A single plural lookup is normally inexpensive, but repeatedly scanning a large page in a loop can add remote WebDriver round trips. Locate the parent once, collect the matches once, and reuse the list for related assertions. If the list is dynamic, re-query only after a known DOM update.

Keep selectors tied to application contracts. Styling classes such as item are often changed by redesigns; a dedicated data-testid="product-card" or accessible role/name can make the test less brittle. Position is inherently fragile: inserting a promotional card before the target changes index 1.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Or skip the browser setup

If your goal is a static visual capture rather than an interactive Selenium test, ScreenshotNeo can return a screenshot with one HTTP request. It handles the browser infrastructure for you:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo documentation for request options and response details. Before capture, it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and whether the request was billed. ScreenshotNeo also provides 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 screenshots per month without a card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account.

Practical checklist

  • Use the plural finder when you need anything other than the first match.
  • Select index 1 for the second result.
  • Use one token with By.CLASS_NAME; use CSS for compound classes.
  • Scope the search to the correct container.
  • Wait until at least two intended elements exist when content loads asynchronously.
  • Re-query after DOM re-renders and guard against stale references.
  • Prefer stable test attributes when position is not the behavior under test.

Frequently Asked Questions

Does Selenium count elements from zero or one?

Selenium returns a collection to your programming language; Python lists and Java lists are zero-based, so the second result is index 1.

Can I select the second class match without collecting all matches?

Yes. An XPath expression such as (//*[contains(concat(' ', normalize-space(@class), ' '), ' item ')])[2] selects it directly, but collecting with find_elements is often clearer and easier to guard.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why does the second element change between test runs?

The DOM may be reordered, filtered, paginated, or re-rendered. Scope the locator, wait for the intended state, and use a stable attribute when order is not guaranteed.

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.