最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - Selenium element raise StaleElementReferenceException even with explicit wait - Stack Overflow

programmeradmin2浏览0评论

When I call the below statement:

WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, tag))).click()

I was periodically getting a StaleElementReferenceException, which I thought shouldn't happen considering the explicit wait I've used.

I had to use the below code fixed the issue but I don't understand why the above can ever raise StaleElementReferenceException in the 1st place.

def click_element_with_retry(driver, tag, seconds):
    # for some reason the element_to_be_clickable by itself is not working, and periodically retruns a StaleElementReferenceException
    end_time = datetime.now() + timedelta(seconds=seconds)
    while datetime.now() < end_time:
        try:
            WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, tag))).click()
            break
        except TimeoutException:
            raise_vba_error_message_and_quit(driver, f"Mars Web element could not be found after timeout", "Timeout Error")
        except StaleElementReferenceException:
            continue

Any suggested reading or thoughts why this might be happening? I'm using a edge driver if that matters

When I call the below statement:

WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, tag))).click()

I was periodically getting a StaleElementReferenceException, which I thought shouldn't happen considering the explicit wait I've used.

I had to use the below code fixed the issue but I don't understand why the above can ever raise StaleElementReferenceException in the 1st place.

def click_element_with_retry(driver, tag, seconds):
    # for some reason the element_to_be_clickable by itself is not working, and periodically retruns a StaleElementReferenceException
    end_time = datetime.now() + timedelta(seconds=seconds)
    while datetime.now() < end_time:
        try:
            WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, tag))).click()
            break
        except TimeoutException:
            raise_vba_error_message_and_quit(driver, f"Mars Web element could not be found after timeout", "Timeout Error")
        except StaleElementReferenceException:
            continue

Any suggested reading or thoughts why this might be happening? I'm using a edge driver if that matters

Share Improve this question edited Mar 11 at 12:56 Guy 51.1k10 gold badges48 silver badges94 bronze badges asked Mar 11 at 12:37 PaMcDPaMcD 11715 bronze badges 3
  • always put full error message because there are other useful information. – furas Commented Mar 11 at 17:25
  • Selenium may keep reference to items in browser memory (instead of Python objects). If you click something then browser may move element in memory and references may be incorrect. After click you may have to search element(s) again to get correct references to object in memory. – furas Commented Mar 11 at 17:28
  • WebDriverWait's polling loop only ignores not found exceptions. Any methods called by the element reference can throw an exception. (Most common would be Stale Element, or Click Intercepted exceptions) In this case the Expected Condition is running some methods of the element reference to see if it's clickable. If the DOM is updated between the time it's found and when one of its methods is run, you'll get a stale element. (meaning it was found, but the element reference is no longer valid) In this case the DOM is probably in the process of updating when you find the element. – browsermator Commented Mar 11 at 18:41
Add a comment  | 

1 Answer 1

Reset to default 1

Have a look at the implementation

def element_to_be_clickable(
    mark: Union[WebElement, Tuple[str, str]]
) -> Callable[[WebDriverOrWebElement], Union[Literal[False], WebElement]]:
    """An Expectation for checking an element is visible and enabled such that
    you can click it.

    element is either a locator (text) or an WebElement
    """

    # renamed argument to 'mark', to indicate that both locator
    # and WebElement args are valid
    def _predicate(driver: WebDriverOrWebElement):
        target = mark
        if not isinstance(target, WebElement):  # if given locator instead of WebElement
            target = driver.find_element(*target)  # grab element at locator
        element = visibility_of(target)(driver)
        if element and element.is_enabled():
            return element
        return False

    return _predicate

The WebElement that is sent to the function (or located in it) calls the functions is_displayed() and is_enabled() (or click() afterwards). Each one of them can cause StaleElementReferenceException if the element reference is lost in the time between the locating and checking.

发布评论

评论列表(0)

  1. 暂无评论