Python Selenium技术问题:实现页面刷新直至按钮可点击并完成点击
Hey Jason, let's troubleshoot and fix your script that's supposed to wait for the "Add to basket" button to be clickable before clicking it. The main issues with your current code are related to element targeting accuracy and not properly checking if the button is actually interactable.
What's Wrong with the Original Code?
- Incorrect XPath Text Matching: The button's text sits alongside an
<span>icon, and there are extra spaces around "Add to basket". Usingtext() = 'Add to basket'won't match because it looks for exact, direct text content without accounting for whitespace or child elements. - No Check for Clickability: Your script tries to click the element as soon as it finds it, but the button might exist in the DOM but be disabled (e.g., have a
disabledattribute) or not yet interactable. - Overly Broad Exception Handling: Catching all exceptions with a bare
except:can hide unrelated errors (like driver issues) and make debugging harder.
Fixed Script
Here's an improved version that addresses these issues using explicit waits (more efficient than constant refreshes) and better element targeting:
from selenium import webdriver 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.common.exceptions import TimeoutException, ElementNotInteractableException print("Opening webpage") options = webdriver.ChromeOptions() options.add_argument("--user-data-dir=C:/Users/pc/AppData/Local/Google/Chrome/User Data/") # Path to your chrome profile driver = webdriver.Chrome(executable_path="chromedriver.exe", options=options) driver.get(page) def main(): wait = WebDriverWait(driver, 10) # Wait up to 10 seconds for the button each cycle while True: try: # Wait for the button to be visible AND clickable, using normalized text to handle spaces add_to_basket_btn = wait.until( EC.element_to_be_clickable( (By.XPATH, "//button[normalize-space(text())='Add to basket']") ) ) add_to_basket_btn.click() print("Successfully clicked 'Add to basket'!") break except (TimeoutException, ElementNotInteractableException): # Only refresh if the button isn't found or isn't clickable within the timeout print("Button not clickable yet, refreshing page...") driver.refresh() continue if __name__ == '__main__': main()
Key Improvements Explained
- Better XPath Targeting:
normalize-space(text())trims extra whitespace and ignores line breaks, so it matches the button's text even if there are spaces around it or child elements like the icon span. - Explicit Wait for Clickability:
EC.element_to_be_clickable()ensures the button is both present in the DOM and enabled/interactable (not grayed out or disabled) before attempting to click it. - Precise Exception Handling: We only catch
TimeoutException(button not found in time) andElementNotInteractableException(button exists but can't be clicked), so other errors will still be visible for debugging. - Efficient Waiting: Instead of refreshing immediately, we wait up to 10 seconds each cycle for the button to become clickable—this reduces unnecessary page refreshes.
Alternative: Target by Parent Container (More Reliable)
If the button's class names change frequently, you can target it via its parent wrapper (which has a stable data-component attribute):
add_to_basket_btn = wait.until( EC.element_to_be_clickable( (By.XPATH, "//div[@data-component='add-to-basket-button-wrapper']/button") ) )
This is often more reliable because data attributes are less likely to change than dynamic class names.
内容的提问来源于stack exchange,提问作者Jason

