Selenium中visibility_of_element_located与element_to_be_clickable的选择方案探讨——针对tvn24.pl登录场景的技术问询
Solution to Your Selenium Visibility & Popup Interaction Issues
Let's tackle your questions first, then refine your code to handle edge cases like disappearing popups.
1. visibility_of_element_located vs element_to_be_clickable in Your Scenario
You're right to question this! Here's the breakdown:
visibility_of_element_locatedchecks if the element exists in the DOM, has dimensions >0, and is visible (including all parent elements being visible). But if your login button exists in the DOM with valid dimensions but is hidden by a parent container (e.g., the popup is collapsed without the--visibleclass), this condition might still pass incorrectly if the parent's visibility is controlled via CSS (likeoverflow: hiddenorheight: 0instead ofdisplay: none).element_to_be_clickableadds an extra check: the element must also be enabled (not disabled via thedisabledattribute). This is more aligned with your goal of clicking the button, but the real fix is to wait for the popup container to be visible first (using thediv.account-standard--visibleselector). This ensures the entire popup is expanded before you try to interact with the login button, which is far more reliable than checking the button alone.
2. Handling Disappearing Popups After Hover
If the popup collapses unexpectedly before you can click the button, here's how to mitigate it:
- Use explicit waits instead of
time.sleep: Waits ensure you only interact with elements when they're ready, reducing race conditions. - Capture interaction exceptions: Catch errors like
ElementNotInteractableExceptionorStaleElementReferenceExceptionand retry the hover-click flow. - Keep the mouse within the popup: After hovering the initial button, move the mouse directly to the login button before clicking—this prevents the popup from closing due to mouse exit.
- Retry with page refresh: If repeated attempts fail, refresh the page to reset the state and try again.
Refined Code Implementation
Here's an optimized version of your function that addresses these issues following Selenium best practices:
from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as ec from selenium.webdriver.common.action_chains import ActionChains from selenium.common.exceptions import ( ElementNotInteractableException, StaleElementReferenceException, TimeoutException ) import time def move_to_login_page_from_main_page(driver): wait = WebDriverWait(driver, 10) # Selectors CSS_ACCOUNT_TOGGLE = "button.account-standard__toggle-button" CSS_VISIBLE_POPUP = "div.account-standard--visible" CSS_LOGIN_BUTTON = "div.account-standard__popup button.account-content__button.account-content__button--large" EXPECTED_URL_FRAGMENT = "account.tvn.pl" MAX_ATTEMPTS = 3 # Limit retries to avoid infinite loops for attempt in range(MAX_ATTEMPTS): try: # Wait for the account toggle button to be ready for interaction account_toggle = wait.until(ec.element_to_be_clickable((By.CSS_SELECTOR, CSS_ACCOUNT_TOGGLE))) # Hover the toggle to expand the popup ActionChains(driver).move_to_element(account_toggle).perform() # Wait for the popup to become visible (via the --visible class) wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, CSS_VISIBLE_POPUP))) # Wait for the login button to be clickable login_button = wait.until(ec.element_to_be_clickable((By.CSS_SELECTOR, CSS_LOGIN_BUTTON))) # Move to the login button then click to keep the popup open ActionChains(driver).move_to_element(login_button).click().perform() # Wait for the page to navigate to the login URL wait.until(ec.url_contains(EXPECTED_URL_FRAGMENT)) print("Successfully redirected to login page!") return except (ElementNotInteractableException, StaleElementReferenceException, TimeoutException) as e: print(f"Attempt {attempt + 1} failed: {str(e)}. Retrying...") time.sleep(1) # Optional: Refresh the page if state seems broken driver.refresh() # If all attempts fail, raise an exception raise Exception(f"Failed to access login page after {MAX_ATTEMPTS} attempts")
Key Improvements:
- Replaced
whileloops with a controlled retry loop usingMAX_ATTEMPTS - Used explicit waits (
WebDriverWait) instead oftime.sleepfor better reliability - Added checks for the popup's visible state before interacting with the login button
- Captured common exceptions to handle unexpected popup behavior
- Kept the mouse within the popup area to prevent collapse
内容的提问来源于stack exchange,提问作者Łukasz Gil
相关产品推荐
相关产品推荐

