How to extract the text out of a list element between a ::before and ::after using Selenium and Python

Question:

I am working on a project for work that automates account generation. For the final piece of selenium I am trying to pull text from a list element and compare the text to confirm they match. I have attached the HTML and along with what I have so far that is getting a AttributeError: 'list' object has no attribute 'text'.

HTML of Element

<li class="account dropdown open">

        <a id="user-salutation" href="#" class="dropdown-toggle" data-toggle="dropdown" segment-event="Expanded User Profile Menu" segment-ui-location="Global Nav" aria-expanded="true"> == 0
                        ::before
                       Hi TQLJOlsen1</a>
                             ::after
        <ul class="dropdown-menu" id="userPreferencesUl">
            <li class="larger"><a class="userPreferencesTrigger" title="Settings">Settings</a></li>
            <li class="larger"><a target="_blank" href="https://account.dat.com?source=Power" title="Account">Account</a></li>
            <li class="larger compactView">
                <a compact-view-toggle="" compact-text="Compact View" normal-text="Normal View" segment-event="Applied [title]" segment-ui-location="Profile" class="ng-isolate-scope" title="Compact View">Compact View</a>
            </li>
            <li class="larger"><a id="changePassword" target="_blank" href="https://account.dat.com?source=Power" title="Change Password">Change Password</a></li>
            <li><hr></li>
            <li class="larger">
                <a id="logout" onclick="logout('/logout');" title="Log Out" segment-event="Logged Out" segment-ui-location="Profile" segment-reset="true">Log Out</a>
            </li>
        </ul>
</li>

The HTML for the specific element

<a id="user-salutation" href="#" class="dropdown-toggle" data-toggle="dropdown" segment-event="Expanded User Profile Menu" segment-ui-location="Global Nav" aria-expanded="true"> == $0
::before
Hi TQLJOlsen1</a>
::after

Script

confirm = (WebDriverWait(driver, 20).until(EC.presence_of_all_elements_located((By.XPATH, '//*[@id="user-salutation"]'))).text)
if confirm.text == ("Hi " + NewUserName):
   print("User Account Created")
else:
   print("Issue occured could not confirm user account created, please confirm creation was succesful")
Asked By: DaHawg

||

Answers:

The line (below) in your code uses EC.presence_of_all_elements_located which returns a list of elements instead of one particular element you’re looking for. And that is the reason for the error you’re getting

confirm = (WebDriverWait(driver, 20).until(EC.presence_of_all_elements_located((By.XPATH, '//*[@id="user-salutation"]'))).text)

The possible solutions are as follows,

1st solution – Replace the above line with the following line. By replacing presence_of_all_elements_located with presence_of_element_located. Note that this would only work if the

confirm = (WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.XPATH, '//*[@id="user-salutation"]'))).text)

2nd solution – Add an index to the list to get the desired element. Here(as shown below), we have assumed that the first element in the list is the element which we are looking for. You can change the index and look if some other element is required

confirm = (WebDriverWait(driver, 20).until(EC.presence_of_all_elements_located((By.XPATH, '//*[@id="user-salutation"]')))[0].text)
Answered By: babban babu

presence_of_all_elements_located() would return a list where as you are expecting a WebElement to extract the text. Hence you see the error:

AttributeError: ‘list’ object has no attribute ‘text’


Solution

To extract the text Hi TQLJOlsen1 ideally you need to induce WebDriverWait for the visibility_of_element_located() which would identify the desired element and you can use either of the following locator strategies:

  • Using CSS_SELECTOR:

    print(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "a#user-salutation"))).text)
    
  • Using XPATH:

    print(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//a[@id='user-salutation']"))).get_attribute("innerHTML"))
    
  • Note : You have to add the following imports :

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    

You can find a relevant discussion in How to retrieve the text of a WebElement using Selenium – Python

Answered By: undetected Selenium