Search code examples
pythonseleniumxpathcss-selectorswebdriverwait

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


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")

Solution

  • 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