XPath with contains and starts-with helps find elements when you only know part of their attribute or text. This makes tests more flexible and less fragile.
XPath with contains and starts-with in Selenium Python
//*[contains(@attribute, 'value')]
//*[starts-with(@attribute, 'value')]contains() checks if the attribute or text has the given substring anywhere.
starts-with() checks if the attribute or text begins exactly with the given substring.
<button> element whose id attribute contains 'submit' anywhere.//button[contains(@id, 'submit')]<a> link element whose visible text starts with 'Log'.//a[starts-with(text(), 'Log')]class attribute containing 'active'.//*[contains(@class, 'active')]<input> element whose name attribute starts with 'user'.//input[starts-with(@name, 'user')]
This script opens a simple HTML page with buttons and links. It uses XPath with contains and starts-with to find elements by partial attribute values and text. It prints the found elements' text or tag name to show the correct elements were found.
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.chrome.options import Options # Setup WebDriver (make sure chromedriver is in PATH) options = Options() options.add_argument('--headless') driver = webdriver.Chrome(options=options) # Open a simple test page with buttons html = ''' <html> <body> <button id="btn_submit_123">Submit</button> <button id="btn_cancel_456">Cancel</button> <a href="#" class="link active">Login</a> <a href="#" class="link">Logout</a> </body> </html> ''' # Use data URL to load HTML driver.get("data:text/html;charset=utf-8," + html) # Find button with id containing 'submit' submit_button = driver.find_element(By.XPATH, "//button[contains(@id, 'submit')]") print(submit_button.text) # Should print 'Submit' # Find link starting with text 'Log' link = driver.find_element(By.XPATH, "//a[starts-with(text(), 'Log')]") print(link.text) # Should print 'Login' # Find element with class containing 'active' active_link = driver.find_element(By.XPATH, "//*[contains(@class, 'active')]") print(active_link.tag_name) # Should print 'a' # Find button starting with id 'btn_cancel' cancel_button = driver.find_element(By.XPATH, "//button[starts-with(@id, 'btn_cancel')]") print(cancel_button.text) # Should print 'Cancel' # Close driver driver.quit()
Always prefer unique and stable attributes for locating elements.
Using contains and starts-with helps when attributes change dynamically.
Test your XPath expressions in browser DevTools before using them in code.
contains() finds elements with attribute or text containing a substring.
starts-with() finds elements with attribute or text starting with a substring.
These XPath functions make locating elements more flexible and reliable.
Practice
id attribute contains the text "submit" anywhere inside it?Solution
Step 1: Understand the contains() function
The contains() function checks if an attribute or text includes a specific substring anywhere inside it.Step 2: Apply contains() to the id attribute
Using contains(@id, 'submit') finds elements where the id attribute has 'submit' anywhere in its value.Final Answer:
contains(@id, 'submit') -> Option BQuick Check:
contains() = substring anywhere [OK]
- Using starts-with() when substring is not at start
- Using ends-with() which is not supported in XPath 1.0
- Using equals() which requires exact match
class attribute starts with "btn-"?Solution
Step 1: Identify the correct function for 'starts with'
The starts-with() function is used to check if an attribute value begins with a specific substring.Step 2: Check XPath syntax
The correct syntax is //element[starts-with(@class, 'btn-')]. Options C and D use invalid XPath syntax for this purpose.Final Answer:
//element[starts-with(@class, 'btn-')] -> Option CQuick Check:
starts-with() = prefix match [OK]
- Using contains() instead of starts-with() for prefix
- Using CSS selector syntax like ^= or *= in XPath
- Missing parentheses in function call
//div[contains(text(), 'Error') and starts-with(@class, 'alert-')]
Assuming the HTML contains:
<div class="alert-danger">Error: Invalid input</div> <div class="alert-success">Success</div> <div class="message-error">Error occurred</div>
Solution
Step 1: Analyze contains(text(), 'Error')
This matches div elements whose visible text includes 'Error'. The first and third divs contain 'Error'.Step 2: Analyze starts-with(@class, 'alert-')
This matches div elements whose class attribute starts with 'alert-'. The first and second divs match this.Step 3: Combine both conditions with AND
Only the first div satisfies both: text contains 'Error' and class starts with 'alert-'.Final Answer:
Selects only the div with class 'alert-danger' -> Option AQuick Check:
AND filters to first div only [OK]
- Assuming contains() matches attribute instead of text
- Ignoring the starts-with() condition
- Selecting all divs with 'Error' ignoring class prefix
//button[contains(@id, 'save-')]
But it also matches buttons with id "disable-save". How to fix it?
Solution
Step 1: Understand why contains() matches unwanted ids
contains(@id, 'save-') matches any id containing 'save-' anywhere, including 'disable-save'.Step 2: Use starts-with() to match only ids beginning with 'save-'
starts-with(@id, 'save-') ensures only ids starting exactly with 'save-' are matched.Final Answer:
//button[starts-with(@id, 'save-')] -> Option AQuick Check:
starts-with() fixes unwanted matches [OK]
- Using contains() when prefix match is needed
- Using ends-with() which XPath 1.0 does not support
- Matching text() instead of attribute
<a> elements where the href attribute starts with "https://" and the link text contains "Learn". Which XPath expression correctly does this?Solution
Step 1: Match href attribute starting with 'https://'
Use starts-with(@href, 'https://') to ensure href begins exactly with 'https://'.Step 2: Match link text containing 'Learn'
Use contains(text(), 'Learn') to find links whose visible text includes 'Learn' anywhere.Step 3: Combine both conditions with AND
Both conditions must be true, so use and between them.Final Answer:
//a[starts-with(@href, 'https://') and contains(text(), 'Learn')] -> Option DQuick Check:
starts-with() + contains() combined correctly [OK]
- Using contains() for href prefix instead of starts-with()
- Swapping text() and attribute in functions
- Using starts-with() on text when contains() is needed
Ready to prove it?
Pass the test and this pattern moves unknown
