Python Selenium get element by CSS matching text - python

Hi I can't figure out how to get an element by CSS and matching with text. I know it can be done with Xpath but I'd rather use CSS.
<div class="button-face">
<div class="button-face-caption"> Text I want to find 1</div>
</div>
<div class="button-face">
<div class="button-face-caption"> Text I want to find 2</div>
</div>
So in by CSS would be something like...
driver.find_element_by_css('div.button-face-caption')
But how can add the text matching to that? i tried with contains and innerText and none seem to work.

As you said it's supported in xpath:
This would be a solution with an xpath using contains and text()
driver.find_element_by_xpath('//div[#class="button-face-caption" and contains(text(),"Text I want to find")]')
The xpath being:
//div[#class="button-face-caption" and contains(text(),"Text I want to find")]
For css, look here: https://sqa.stackexchange.com/q/362/34209 which should allow us to use:
div:contains('Text I want to find')
Which would lead us to
driver.find_element_by_css("div:contains('Text I want to find')")
However this comes with a BIG caveat:
:contains() is not part of the current CSS3 specification so it will
not work on all browsers, only ones that implemented it before it was
pulled. (see w3.org/TR/css3-selectors)

As workaround you can create your own function
def find_by_css(selector, text=''):
return [element for element in driver.find_elements_by_css_selector(selector) if text in element.text][0]
Then you can call it as
find_by_css('div.button-face-caption') # search only by CSS-selector
or
find_by_css('div.button-face-caption', 'Text I want to find 2') # search by CSS + text

As per the following discussions:
CSS selector :contains doesn't work with Selenium
css pseudo-class :contains() no longer allows anchors
The :contains pseudo-class isn't in the CSS Spec and is not supported by either Firefox or Chrome (even outside WebDriver).
Solution
You need to consider the ancestor of the <div class="button-face"> element and traverse down. Let us assume that both the <div class="button-face"> are with in a parent <div class="class">:
<div class="class">
<div class="button-face">
<div class="button-face-caption"> Text I want to find 1</div>
</div>
<div class="button-face">
<div class="button-face-caption"> Text I want to find 2</>
</div>
</div>
So to identify the element with text as:
Text I want to find 1:
div.class div:first-child > div.button-face-caption
Text I want to find 2:
div.class div:nth-child(2) > div.button-face-caption
References
You can find a couple of relevant detailed discussions in:
selenium.common.exceptions.InvalidSelectorException with “span:contains('string')”
Finding link using text in CSS Selector is not working

Related

Find element by CSS selector AFTER certain element with Selenium

I'm looking to get the text "Interesting" which is the first occurrence of the class b after h1.important.
How would I do that in Selenium?
<div class="a">
<div class="b">Not interesting</div>
</div>
<div class="title">
<h1 class="important">Title</h1>
</div>
<div class="a">
<div class="b">Interesting</div>
</div>
Is there a way to find "Interesting" using a fancy selector or xpath?
This would also match the first element: driver.find_elements_by_css_selector(".b").text
driver.find_elements_by_css_selector(".b")
this will return a list in Python-Selenium bindings. so you cannot do .text on it.
Instead try to use driver.find_element like below :
driver.find_element_by_css_selector("div.title+div>.b").text
in case you want to use xpath, try this :
driver.find_element_by_xpath("//div[#class='title']/following-sibling::div/div").text
Note that, CSS_SELECTOR is preferred over xpath in Selenium automation.
This XPath
//h1[#class='important']/../following-sibling::*//*[#class='b']
Should give you the next b class occurrence after the h1.important node as you asking
This xpath should work
(//h1[#class="important"]/following::*[#class='b'])[1]

Python Selenium find element with following sibling by class, id, a (hreff or class)

I need help with finding an exact element and click it with following-sibling based on specific id number and then classes and a (href or class).
Here is simplified code, the below example occurs many times just with different id:
<div class="class_1" id="1234567">
<div class="class_2">
<div class="class_3">
<div class="class_3.1">
<div class="class_3.2">
<div class="class_3.3">
<div class="class_3.3.1">
<div class="class_3.3.1.1">
<div class="class_3.3.1.2">
<div class="class_3.3.1.3">
...
How can I locate an element with id and class for example something like this and click on it:
driver.find_element(By.XPATH, 'class=class_1 and id="2222222" and class="event-media-icon live-icon icon-white').click()
The xpath you are looking for will look like the following:
//div[#class='class_1' and(#id='1234567')]//a[#data-sport='soccer']
I guess the elements between the upper div and the goal a are not important so we can omit them.
The href value looks not unique too so I preferred using data-sport attribute that can be more unique.
To give more precise answer I need to see that web page with dev tools.
This xpath should work fine too
.//div[#class='class_1' and #id='1234567']//following-sibling::a[#data-sport='soccer']

How to get WebElement text only for direct child?

I'm working with Python Selenium, and in the following HTML structure:
<div>
<h2>Welcome</h2>
<div>
<p>some text <strong>important</strong></p>
<a>link</a>
</div>
</div>
I'd like to get the text from each descendant (h2, div, p, strong, a) of the parent div, e.g. for the <p> tag I want some text.
I've been using the .text attribute and getting some text important instead. I'd like to use something similar as the BeautifulSoup attribute .string.
Edit: I need the code to work for any parent element containing descendants with more nested descendants - not just this particular HTML structure.
Thanks for your help.
Use Java Script executor to return textContent.
print(driver.execute_script('return arguments[0].firstChild.textContent;', driver.find_element_by_xpath("//h2[contains(.,'Welcome')]/following::div/p")))

Returning a list of values from a list of dictionaries where keys equal a certain value

<div id="tabs" class="clearfix">
<ul id="remove">
<li class="btn_arrow_tab left inactive">
<a href="#" class="doubleText">Pay Monthly <small>View standard rates and Bolt Ons</small>
</a>
</li>
<li class="btn_arrow_tab right inactive">
<a href="#" class="doubleText">Pay & Go<small>View standard rates and Bolt Ons</small>
</a>
</li>
</ul>
</div>
I have no experience in webscraping and trying to follow example and the docs to click on the button with text 'Pay Monthly'. This button then dynamically displays some text which I need to copy. How do I go about clicking this for starters, and then reading the text which is displayed. I am trying it with Selenium, would beautifulsoup be better? I have been trying this line of code but it isn't doing anything:
driver.find_element_by_xpath("//a[text()[contains(.,'Pay Monthly')]]").click()
It is always good practice to use mixture of absolute and relative xpath to locate a element.
First thing you should find is a parent that has a unique identifier. The element you mentioned has two parent items with a static id. One is root div and another is ul.
Now either we can follow your path and find the element using Text. Any of the following shall work.
driver.find_element_by_xpath("//div[#id='tabs']//a[text()[contains(.,'Pay Monthly')]]").click()
driver.find_element_by_xpath("//ul[#id='remove']//a[text()[contains(.,'Pay Monthly')]]").click()
But, if the item is static element and considering your goal here, I would suggest the following method. indexing your xpath when it returns multiple elements.
myElement = driver.find_element_by_xpath("//div[#id='tabs']//a[#href='#'][1]")
myElement.click()
And then you can capture the text. You can put some wait to ensure the text gets changed.
myText = myElement.text
Let me know if this doesn't work.

Selenium-Python: Class containing link-text

I am using Python & Selenium to scrap the content of a certain webpage. Currently, I have the following problem: There are multiple div-classes with the same name, but each div-class has different content. I only need the information for one particular div-class. In the following example, I would need the information in the first "show_result"-class since there is the "Important-Element" within the link text:
<div class="show_result">
<a href="?submitaction=showMoreid=77" title="Go-here">
<span class="new">Important-Element</span></a>
Other text, links, etc within the class...
</div>
<div class="show_result">
<a href="?submitaction=showMoreid=78" title="Go-here">
<span class="new">Not-Important-Element</span></a>
Other text, links, etc within the class...
</div>
<div class="show_result">
<a href="?submitaction=showMoreid=79" title="Go-here">
<span class="new">Not-Important-Element</span></a>
Other text, links, etc within the class...
</div>
With the following code I can get the "Important-Element" and its link:
driver.find_element_by_partial_link_text('Important-Element'). However, I also need the other information within the same div-class "show-result". How can I refer to the entire div-class that contains the Important-Element in the link text? driver.find_elements_by_class_name('show_result') does not work since I do not know in which of the div-classes the Important-Element is located.
Thanks,
Finn
Edit / Update: Ups, I found the solution on my own using xpath:
driver.find_element_by_xpath("//div[contains(#class, 'show_result') and contains(., 'Important-Element')]")
I know you've found an answer but I believe it's wrong since you would also select the other nodes because Important-Element is still in Non-Important-Element.
Maybe it works for your specific case since that's not really the text you're after. But here are a few more answers:
//div[#class='show_result' and starts-with(.,'Important-Element')]
//div[span[text()='Important-Element']]
//div[contains(span/text(),'Important-Element') and not(contains(span/text(),'Non'))]
There are more ways to write this...
Ups, i found the solution on my own via xpath:
driver.find_element_by_xpath("//div[contains(#class, 'show_result') and contains(., 'Important-Element')]")

Categories

Resources