finding web element containing specific text gives different result when we use variable as search text in python selenium

Viewed 71

I am using selenium in python
I am searching for specific text on webpage then I display the text of coresponding web element
This code works alright

from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--log-level=3")
driver = webdriver.Chrome(options=chrome_options)
url = 'https://tophunt.in/amazon-quiz-14-march-2021/'
driver.get(url)
sourcecode = driver.page_source
if 'Answer 1' in sourcecode:
    print('Answer 1 text found in source code of webpage')
    answeroneele = driver.find_elements_by_xpath("//*[contains(text(), 'Answer 1')]")
    print(len(answeroneele), 'having Answer 1')
    input('wait')
    for elements in answeroneele:
        full_answer = elements.get_attribute('textContent')
        print(full_answer)
driver.quit()

But if I use variable in searching web element then I get 553 elements that match . Looks like whole web page got printed. The code is

from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--log-level=3")
driver = webdriver.Chrome(options=chrome_options)
url = 'https://tophunt.in/amazon-quiz-14-march-2021/'
driver.get(url)
sourcecode = driver.page_source
str_to_search = 'Answer 1'
if 'Answer 1' in sourcecode:
    print('Answer 1 text found in source code of webpage')
    answeroneele = driver.find_elements_by_xpath("//*[contains(text(), str_to_search)]")
    print(len(answeroneele), 'having Answer 1')
    input('wait')
    for elements in answeroneele:
        full_answer = elements.get_attribute('textContent')
        print(full_answer)
driver.quit()

Why this happens?

Thanks.

3 Answers

The contains function determines whether the first argument string contains the second argument string and returns boolean true or false. It operates on strings, but if object of any other type is passed then it is converted to string using the string function.

  • text() is a selector that matches all text nodes that are children of the context node and it returns a node set.
  • If a node set is passed to the string function it returns the string-value of the node in the node-set that is first in document order. If the node set is empty then an empty string is returned.

In contains(text(), str_to_search) when the string function is applied on str_to_search it returns an empty string hence it matches every children of the context node that contains any text.

To solve this issue you can use string interpolation

  • For python versions >= 3.6 you can use f-strings
driver.find_elements_by_xpath(f"//*[contains(text(), '{str_to_search}')]")
  • For older python versions you can use str.format
driver.find_elements_by_xpath("//*[contains(text(), '{}')]".format(str_to_search))

You wrote str_to_search inside double-quotes, so to python it's just part of a string literal. What you want is for python to replace the value of that variable (doing so-called string interpolation), you can use the f-string syntax for this:

answeroneele=driver.find_elements_by_xpath(f"//*[contains(text(), '{str_to_search}')]")

Note the f before the opening quote and the {} around the variable name.

You have to use string interpolation in python {variable}

answeroneele=driver.find_elements_by_xpath("//*[contains(text(), '{str_to_search}')]")
Related