I'm trying to test a complicated JavaScript interface with Selenium (using the Python interface, and across multiple browsers). I have a number of buttons of the form:
<div>My Button</div>
I'd like to be able to search for buttons based on "My Button" (or non-case-sensitive, partial matches such as "my button" or "button").
I'm finding this amazingly difficult, to the extent to which I feel like I'm missing something obvious. The best thing I have so far is:
driver.find_elements_by_xpath('//div[contains(text(), "' + text + '")]')
This is case-sensitive, however. The other thing I've tried is iterating through all the divs on the page, and checking the element.text property. However, every time you get a situation of the form:
<div class="outer"><div class="inner">My Button</div></div>
div.outer also has "My Button" as the text. To fix that, I've tried looking to see if div.outer is the parent of div.inner, but I couldn't figure out how to do that (element.get_element_by_xpath('..') returns an element's parent, but it tests not equal to div.outer).
Also, iterating through all the elements on the page seems to be really slow, at least using the Chrome webdriver.
Ideas?
I asked (and answered) a more specific version here: How to get text of an element in Selenium WebDriver, without including child element text?
Try the following:
driver.find_elements_by_xpath("//*[contains(text(), 'My Button')]")
In the HTML which you have provided:
<div>My Button</div>
The text My Button is the innerHTML and have no whitespaces around it so you can easily use text() as follows:
my_element = driver.find_element_by_xpath("//div[text()='My Button']")
Note: text() selects all text node children of the context node
Text with leading/trailing spaces
In case the relevant text containing whitespaces either in the beginning:
<div> My Button</div>
or at the end:
<div>My Button </div>
or at both the ends:
<div> My Button </div>
In these cases you have two options:
You can use contains() function which determines whether the first argument string contains the second argument string and returns boolean true or false as follows:
my_element = driver.find_element_by_xpath("//div[contains(., 'My Button')]")
You can use normalize-space() function which strips leading and trailing white-space from a string, replaces sequences of whitespace characters by a single space, and returns the resulting string as follows:
driver.find_element_by_xpath("//div[normalize-space()='My Button']]")
XPath expression for variable text
In case the text is a variable, you can use:
foo= "foo_bar"
my_element = driver.find_element_by_xpath("//div[.='" + foo + "']")
You could try an XPath expression like:
'//div[contains(text(), "{0}") and #class="inner"]'.format(text)
//* will be looking for any HTML tag. Where if some text is common for Button and div tag and if //* is categories it will not work as expected. If you need to select any specific then You can get it by declaring HTML Element tag. Like:
driver.find_element_by_xpath("//div[contains(text(),'Add User')]")
driver.find_element_by_xpath("//button[contains(text(),'Add User')]")
You can also use it with Page Object Pattern, e.g:
Try this code:
#FindBy(xpath = "//*[contains(text(), 'Best Choice')]")
WebElement buttonBestChoice;
Interestingly virtually all answers revolve around XPath's function contains(), neglecting the fact it is case sensitive - contrary to the OP's ask.
If you need case insensitivity, that is achievable in XPath 1.0 (the version contemporary browsers support), though it's not pretty - by using the translate() function. It substitutes a source character to its desired form, by using a translation table.
Constructing a table of all upper case characters will effectively transform the node's text to its lower() form - allowing case-insensitive matching (here's just the prerogative):
[
contains(
translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
'my button'
)
]
# will match a source text like "mY bUTTon"
The full Python call:
driver.find_elements_by_xpath("//*[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZЙ', 'abcdefghijklmnopqrstuvwxyzй'), 'my button')]")
Naturally this approach has its drawbacks - as given, it'll work only for Latin text; if you want to cover Unicode characters - you'll have to add them to the translation table. I've done that in the sample above - the last character is the Cyrillic symbol "Й".
And if we lived in a world where browsers supported XPath 2.0 and up (🤞, but not happening any time soon ☹️), we could having used the functions lower-case() (yet, not fully locale-aware), and matches (for regex searches, with the case-insensitive ('i') flag).
Simply use This:
driver.find_elements_by_xpath('//*[text() = "My Button"]')
Similar problem: Find <button>Advanced...</button>
Maybe this will give you some ideas (please transfer the concept from Java to Python):
wait.until(ExpectedConditions.elementToBeClickable(//
driver.findElements(By.tagName("button")).stream().filter(i -> i.getText().equals("Advanced...")).findFirst().get())).click();
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(text(), 'YourTextHere')]")));
assertNotNull(driver.findElement(By.xpath("//*[contains(text(), 'YourTextHere')]")));
String yourButtonName = driver.findElement(By.xpath("//*[contains(text(), 'YourTextHere')]")).getAttribute("innerText");
assertTrue(yourButtonName.equalsIgnoreCase("YourTextHere"));
Use driver.find_elements_by_xpath and matches regex matching function for the case insensitive search of the element by its text.
driver.find_elements_by_xpath("//*[matches(.,'My Button', 'i')]")
If using C#
ChromeOptions options = new ChromeOptions();
var driver = new ChromeDriver(options);
var urlLink = "https://www.pexels.com/tr-tr/arama/do%C4%9Fa/";
driver.Navigate().GoToUrl(urlLink);
Thread.Sleep(10000);
var divList = driver.FindElementsByXPath(".//div[contains(#class,'hide-featured-badge')]");
foreach (var divItem in divList)
{
var photoOwnerName = divItem.FindElement(By.XPath(".//span[#class='photo-item__name']")).GetAttribute("innerHTML");
}
Try this. It's very easy:
driver.getPageSource().contains("text to search");
This really worked for me in Selenium WebDriver.
I want to find a web element that contains text 'My' .But the text is stored in a variable named msg
msg = "My"
How do I use the variable in the xpath and find the web element . I also want to click the element
below code works if I give the text directly in the xpath . But i want to use the variable msg to generalize
driver.find_elements_by_xpath("//*[contains(text(), 'My')]")
driver.find_element_by_xpath("//*[contains(text(), '{}')]".format(msg))
Just use format.
You can use text equals as well:
driver.find_element_by_xpath("//*[text()='{}']".format("you_text"))
but I agree, contains is more flexible:
driver.find_element_by_xpath("//*[contains(text(),'{}')]".format("you_text"))
I'm trying to create a program that clicks on boxes that contain a certain word, however all of the boxes have other words around them.
For example the site has a bunch of recipes, however I just want the ones that contain the word "soup". So it needs to be able to click on text that say, "tomato soup, "yummy soup", "some other soup type soup", and so on.
I've found this line.
WebDriverWait(driver, 10).until(expected_conditions.element_to_be_clickable((By.XPATH, "//span[text()='Soup']"))).click()
which is great but only works if you put the exact text in it.
Ex. WebDriverWait(driver, 10).until(expected_conditions.element_to_be_clickable((By.XPATH, "//span[text()='Tomato Soup']"))).click()
If anyone knows how to do a more loose find that would be a big help. Thank You.
If you are using XPath 2.0 you could use a regular expression so look for everything that contains Soup.
//*[matches(#id, '.*Soup.*')]
Maybe take a look at How to use regex in XPath "contains" function.
Update
browser = webdriver.Chrome()
browser.get("https://www.allrecipes.com/search/results/?wt=Soup&sort=re&page=10")
elems = browser.find_elements_by_xpath("//span[contains(text(), 'Soup')]")
for elem in elems[:2]:
print(elem.text)
If I have some HTML:
<span class="select2-selection__rendered" id="select2-plotResults-container" role="textbox" aria-readonly="true" title="50">50</span>
And I want to find it using something like:
driver.find_element_by_xpath('//*[contains(text(), "50")]')
The problem is that there is 500 somewhere before on the webpage and it's picking up on that, is there way to search for a perfect match to 50?
Instead of contains, search for a specific text value:
driver.find_element_by_xpath('//*[text()="50"]')
And if you know it will be a span element, you can be a little more specific:
driver.find_element_by_xpath('//span[text()="50"]')
Note that your question asks how to find an element by its text value. If possible and would apply to your situation, you should look for a specific class or id, if known and consistent.
You can search for it by its absolute Xpath. For that, inspect the page and find the element. Then right-click it and copy its Xpath or full Xpath.
Otherwise you can use the id:
driver.find_element_by_id("select2-plotResults-container")
Here is more on locating elements.
use something like this
msg_box=driver.find_element_by_class_name('_3u328') and driver.find_element_by_xpath('//div[#data-tab = "{}"]'.format('1'))
verify alignment of text or any other element in web page using selenium rc.
i use python,
is there any budy who can help with this.
you can utilize getAttribute command for example
String align = selenium.getAttribute("ele_locator#align");
In case text alignment is coded directly in HTML you could do what you want using the assertElementPresent() method and a suitable XPath locator. For example to check the following text
<p id="paragraph" align="right">Text text text text text text text</p>
you could use
selenium.isElementPresent("//p[#id='paragraph' and #align='right']");