0

I am trying to do logout on a web page by selenium and python, and currently no luck. In order to do a logout, I need to click the link at the upper right corner of the web page, and it will have a small drop-down window open, and then I can click the "logout" icon inside this drop-down window. Here is the picture of this drop down window. enter image description here

And the inspect code for this logout icon in the dropdown window.

enter image description here

Now in my python code, I was able to have the drop-down window open, but if I was to click the logout icon, I keep getting exception of "selenium.common.exceptions.ElementNotVisibleException".

Here is my code:

try:
    # to click the link so that the drop-down window opens 
    action = ActionChains(self.driver)
    dropdownwindow= self.driver.find_element_by_xpath("//span[@class='ssobanner_logged']/img")
    action.move_to_element(dropdownwindow).perform()
    dropdownwindow.click()

    # try to click the logout icon in the drop-down so that user may logout 
    logoutLink = self.driver.find_element_by_xpath(
        "//*[@id='ctl00_HeaderAfterLogin1_DL_Portals1']/tbody/tr/td[4]/a/img")
    action.move_to_element(logoutLink).perform()
    logoutLink.click()
    return True
except Exception as e:
    self.logger.info(e)
    raise
return False

And I have got such exceptions during the run time.

selenium.common.exceptions.NoSuchElementException: 
Message: no such element: Unable to locate element: 
 {"method":"xpath","selector":"//*[@id='ctl00_HeaderAfterLogin1_DL_Portals1']/tbody/tr/td[4]/a/img"}

Does anyone know a better way to handle that, other than the xpath I was using ?

Guy
  • 46,488
  • 10
  • 44
  • 88
user3595231
  • 711
  • 12
  • 29

2 Answers2

1

The problem is most likely that the dropdown menu has not fully been expanded/rendered after it is clicked. While a time.sleep(1) command could be a potential fix, a more appropriate fix is a dynamic wait using WebDriverWait:

from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.ui import WebDriverWait

by = By.XPATH  # This could also be By.CSS_SELECTOR, By.Name, etc.
hook = "//*[@id='ctl00_HeaderAfterLogin1_DL_Portals1']/tbody/tr/td[4]/a/img"
max_time_to_wait = 10  # Maximum time to wait for the element to be present
WebDriverWait(driver, max_time_to_wait).until(expected_conditions.element_to_be_clickable((by, hook)))

expected_conditions can also wait using visibility_of_element_located or presence_of_element_located

Brydenr
  • 798
  • 1
  • 19
  • 30
  • I have just tried, If I have Explicit Wait added, I got this type of exception: " selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document " . – user3595231 Mar 05 '20 at 20:20
  • That exception is occurring because the page is refreshing or rebuilding after you get a handle on the element. The explicit wait (`time.sleep`) is also more fragile and likely to either break, or wait longer than necessary. – Brydenr Mar 05 '20 at 21:01
  • Then how may I make sure it works ? To wait extra longer time ? When I have it running in regular mode, I do see the drop down window, but it is exits with such exception in the end. – user3595231 Mar 05 '20 at 21:18
1

Once the drop-down window opens up to click on the icon with text as Logout you need to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following Locator Strategies:

  • Using CSS_SELECTOR:

    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "span.portals-separator +table td>a[title='Log out'][data-mkey='Logout']>img"))).click()
    
  • Using XPATH:

    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[text()='Support and Settings']//following-sibling::table[1]//td/a[@title='Log out' and @data-mkey='Logout']/img"))).click()
    
  • 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
    
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352