Hi I am trying to locate an element by its class name and the text that it contains
<div class="fc-day-number">15</div>
there are a bunch of fc-day-number
on the page with different values, I need the one with for example 15.
I do
driver.find_element_by_class_name("fc-day-content")
but I also need it to be equal to 15 and I am stuck here, please help.
Luckily, Selenium offers a few methods you can use to find elements. One of the options the Selenium WebDriver library provides for locating HTML elements is the use of the class property. The HTML class property is used for setting a class to an HTML element.
We can find an element that contains specific text with Selenium webdriver in Python using the xpath. This locator has functions that help to verify a specific text contained within an element. The function text() in xpath is used to locate a webelement depending on the text visible on the page.
text(): A built-in method in Selenium WebDriver that is used with XPath locator to locate an element based on its exact text value.
We can get text from a webelement with Selenium webdriver. The getText() methods obtains the innerText of an element. It fetches the text of an element which is visible along with its sub elements. It ignores the trailing and leading spaces.
You can use xpath:
driver.find_element_by_xpath("//div[@class='fc-day-content' and text()='15']")
fc_day_contents = driver.find_elements_by_class_name("fc-day-content")
the_one_you_want = [x for x in fc_day_contents if "15" == x.text][0]
first line puts all elements with class name "fc-day-content" in a list ( also notice how its elementSSSSSSSSS with an S, this returns a list of all elements by_class_name, by_name, by_id or wahtever)
second line, goes through each element and looks to see if it has the text "15" as its text, and returns it as a (probably smaller) list
the [0] at the end of it, returns the first item in the list (you can remove it, if you want a list of all the ones that are "15" )
For things like this, prefer to use JavaScript:
els = driver.execute_script("""
return Array.prototype.slice.call(document.getElementsByClassName("fc-day-content"))
.filter(function (x) { return x.textContent === "15"; });
""")
assert len(els) == 1
el = els[0]
What this does is get all elements that have the class fc-day-content
as the class. (By the way, your question uses fc-day-content
and fc-day-number
. Unclear which one you're really looking for but it does not matter in the grand scheme of things.) The call to Array.prototype.slice
creates an array from the return value of getElementsByClassName
because this method returns an HTMLCollection
and thus filter
is not available on it. Once we have the array, run a filter
to narrow it to the elements that have 15
for text. This array of elements is returned by the JavaScript code. The assert is to make sure we don't unwittingly get more than one element, which would be a surprise. And then the element is extracted from the list.
(If you care about IE compatibility, textContent
is not available before IE 9. If you need support for IE 8 or earlier, you might be able to get by with innerText
or innerHTML
or you could check that the element holds a single text node with value 15
.)
I prefer not to do it like TehTris does (find_elements_by_class_name
plus a Python loop to find the one with the text) because that method takes 1 round-trip between Selenium client and Selenium server to get all the elements of class fc-day-content
plus 1 round-trip per element that was found. So if you have 15 elements on your page with the class fc-day-content
, that's 16 round-trips. If you run a test through Browser Stack or Sauce Labs, that's going to slow things down considerably.
And I prefer to avoid an XPath expression with @class='fc-day-content'
because as soon as you add a new class to your element, this expression breaks. Maybe the element you care about has just one CSS class now but applications change. You could use XPath's contains()
function but then you run into other complications, and once you take care of everything, it becomes a bit unwieldy. See this answer for how to use it robustly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With