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

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 finder, then read the item at zero-based index 1. In Python:

from selenium.webdriver.common.by import By

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

find_element (singular) always returns the first matching element. find_elements returns every match in document order, so the second match is index 1, not 2. Selenium documents this distinction in its element-finder guide.

The direct solution

When several elements have the same class token, do not call find_element and expect it to choose the second one. That method is intentionally limited to the first match. Call find_elements, verify that at least two elements were returned, and select position 1.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from selenium.webdriver.common.by import By

matches = driver.find_elements(By.CLASS_NAME, "item")
if len(matches) < 2:
    raise LookupError(f"Expected at least 2 .item elements, found {len(matches)}")

second = matches[1]
print(second.text)
second.click()

The returned list follows the page’s document order. A dynamic page can add, remove, or reorder nodes, so take the list after the page has reached the state you intend to test.

Why find_element is not enough

Selenium’s singular finder returns a reference to the first element found. The plural finder returns all matching references and returns an empty list when there are no matches. This is why the following code cannot select the second item:

first = driver.find_element(By.CLASS_NAME, "item")

Use the plural form whenever your test needs to choose by position, count the matches, or assert that a page rendered the expected number of components. See Selenium’s Finding web elements documentation for the supported pattern.

Python: complete examples

Basic class-name lookup

from selenium import webdriver
from selenium.webdriver.common.by import By

 driver = webdriver.Chrome()
try:
    driver.get("https://example.com/products")
    items = driver.find_elements(By.CLASS_NAME, "item")

    if len(items) < 2:
        raise AssertionError(f"Need two items, got {len(items)}")

    second_item = items[1]
    print(second_item.get_attribute("outerHTML"))
finally:
    driver.quit()

Remove the accidental leading space before driver = if you paste this into a file; Python indentation must be consistent. The important operations are the plural finder, the length check, and index 1.

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

Waiting for the second match on an asynchronous page

If JavaScript inserts the elements after navigation, an immediate lookup may return zero or one result. Wait until the collection contains at least two elements:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait

wait = WebDriverWait(driver, 15)

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

items = wait.until(at_least_two)
second_item = items[1]

The wait function returns the current list once the condition is true. If the condition never becomes true, Selenium raises a timeout rather than an index error.

Restricting the search to a container

Class names are often reused in headers, sidebars, cards, and dialogs. Locate the intended parent first, then search within it:

from selenium.webdriver.common.by import By

catalog = driver.find_element(By.ID, "catalog")
items = catalog.find_elements(By.CLASS_NAME, "item")
if len(items) < 2:
    raise AssertionError("The catalog has fewer than two items")
second_item = items[1]

Searching from a parent prevents unrelated .item elements elsewhere in the document from changing which element is considered second. Selenium supports finding descendants from an already located element.

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

Use CSS selectors for multiple class tokens

By.CLASS_NAME accepts one class token. If the target must have both item and active, use a CSS selector with adjacent class selectors:

matches = driver.find_elements(By.CSS_SELECTOR, ".item.active")
if len(matches) < 2:
    raise LookupError("Fewer than two active items")
second = matches[1]

Do not pass a space-separated string to By.CLASS_NAME:

# Wrong: this is two class tokens, not one
matches = driver.find_elements(By.CLASS_NAME, "item active")

Selenium’s locator strategies identify CSS selector as the option for selector expressions. The Java By API likewise says that className is for one class and directs multi-class matching to cssSelector.

CSS positional selectors versus list indexing

You can express a position in CSS, but CSS position has different semantics depending on the selector. For example, .item:nth-of-type(2) means an .item that is the second element of its tag type among siblings; it does not necessarily mean the second .item anywhere on the page. Fetching all matches and using index 1 is usually clearer when your requirement is “the second result returned by this locator.”

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

Java: selecting the second match

Java’s findElements returns a List<WebElement>. Lists are also zero-based, so call get(1) after checking the size:

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;

WebDriver driver = new ChromeDriver();
try {
    driver.get("https://example.com/products");
    List<WebElement> matches = driver.findElements(By.className("item"));

    if (matches.size() < 2) {
        throw new IllegalStateException("Expected at least two .item elements");
    }

    WebElement second = matches.get(1);
    System.out.println(second.getText());
} finally {
    driver.quit();
}

For two class tokens, replace the locator with By.cssSelector(".item.active"). The same size check protects get(1) from IndexOutOfBoundsException.

Choosing a robust locator

Requirement Locator Example
One class token By.CLASS_NAME find_elements(By.CLASS_NAME, "item")
Several class tokens By.CSS_SELECTOR find_elements(By.CSS_SELECTOR, ".item.active")
Only items in a component Find parent, then descendants panel.find_elements(By.CLASS_NAME, "item")
Stable semantic hook Use a dedicated attribute when available [data-testid='product']

Position is inherently less stable than a unique identifier. If the application can provide a reliable id, data-testid, or other component-specific attribute, prefer that. If the requirement genuinely is “second card,” retain the positional selection but scope it to the correct container.

Handling stale and changing elements

StaleElementReferenceException

A framework re-render can replace the nodes after you collected them. The old references then become stale. Re-locate the list immediately before interacting, and avoid keeping WebElement objects across a known refresh:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
driver.find_element(By.ID, "refresh").click()
wait.until(lambda d: len(d.find_elements(By.CLASS_NAME, "item")) >= 2)
second = driver.find_elements(By.CLASS_NAME, "item")[1]
second.click()

Unexpected ordering

Check the text or an identifying attribute before clicking. This catches hidden placeholders, ads, pinned cards, and responsive rearrangements:

items = driver.find_elements(By.CSS_SELECTOR, "#catalog .item")
for i, item in enumerate(items):
    print(i, item.text, item.get_attribute("data-id"))

Hidden or duplicate nodes

find_elements returns matching DOM elements, including elements that may not be visible. If visibility matters, filter with is_displayed() or use an explicit wait for visibility. Be careful: filtering changes the meaning of “second”—it becomes the second visible match, not the second DOM match.

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

Common errors and fixes

  • Only the first element is returned: replace find_element with find_elements.
  • IndexError or IndexOutOfBoundsException: fewer than two matches existed; check length or wait for the intended state.
  • InvalidSelectorException with a class locator: a space-separated class string was supplied; use one token or a CSS selector such as .item.active.
  • The wrong second element is clicked: scope the search to a parent container and inspect the returned order and attributes.
  • Timeout while waiting: verify the class spelling, iframe context, authentication state, and whether the page actually creates two matching nodes.
  • No matches inside an iframe: switch into the correct frame before locating descendants, then switch back when finished.
  • Element is present but not clickable: wait for visibility or clickability, scroll it into view, and check for an overlay or consent dialog.

Testing and maintenance checklist

  1. Confirm the locator matches the intended component, not every use of a generic class.
  2. Use find_elements and index 1 only after asserting there are at least two results.
  3. Wait for asynchronous rendering when the list is populated after navigation.
  4. Log text or stable attributes while diagnosing ordering failures.
  5. Re-find elements after a page update that can replace DOM nodes.
  6. Prefer stable test attributes over styling classes when your team controls the markup.

Or skip the browser setup

If your goal is to capture a page image rather than interact with the second element, ScreenshotNeo makes a screenshot with one HTTP request. It accepts cookie and consent banners like a visitor, then removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be disabled. 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. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

See the ScreenshotNeo API documentation for all options, including full-page and element capture, device presets, custom CSS and JavaScript, waits, request blocking, cookies, headers, geolocation, PDF output, caching, signed links, asynchronous jobs, bulk capture, and usage reporting.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The Free plan includes 1,000 screenshots per month without a card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan. Create a free ScreenshotNeo account.

Frequently Asked Questions

Is the second Selenium element index 1 or 2?

Index 1. Python lists and Java lists are zero-based, so index 0 is the first result and index 1 is the second.

Can I use XPath to select the second class match?

Yes, but use a carefully scoped XPath and still verify the result. For most class-based cases, Selenium’s plural finder plus index 1 is easier to read and maintain.

What happens when there is only one matching element?

The plural finder returns a one-item list. Accessing index 1 or Java get(1) then fails, so check the collection length or wait for a second match.

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

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.