selenium python onclick() gives StaleElementRefere

2019-08-20 07:30发布

问题:

The developer changed the code to use an onclick() DOM element instead of an url. So Now I need to reload page all the time to prevent it from getting stale. How can I do this with a single find_elements_by_xpath? I assume it is the document.*.submit() that needs the DOM?

https://localhost:4778/ruleengine/AlarmTest?category=Alert#, text:(Force), onclick():document.Forceee0deabfba2341d2a0988779499f5530.submit()

Old code now fails:

driver.get(alarmurl)
elems = driver.find_elements_by_xpath("//a[contains(text(), '(Force)')]")
for el in elems:
    el.click()

My current workaround is to reload the page after every click, but we may have 3000 events to remove, making it horrendously slow.

driver.get(alarmurl)
elems = driver.find_elements_by_xpath("//a[contains(text(), '(Force)')]")
while len(elems) > 0:
    driver.get(alarmurl)
    elems = driver.find_elements_by_xpath("//a[contains(text(), '(Force)')]")
    elems[0].click()

Thanks

回答1:

I dont think you have to reload the entire page if you encounter StaleElementReferenceException but I may be wrong too. It happens When the element is no longer attached to the DOM, search for the element again to reference the element

The below code may not clear your issue, but should help you start implementing a better solution

driver.get(alarmurl)
elems = driver.find_elements_by_xpath("//a[contains(text(), '(Force)')]")
for el in elems:
    try:
      el.click()
    except StaleElementReferenceException:
       # find the element again and click


回答2:

You can fix your code as below:

driver.get(alarmurl)
# get initial events number
elems_count = len(driver.find_elements_by_xpath("//a[contains(text(), '(Force)')]"))

# execute click() for each event
for _ in range(elems_count):
    driver.find_elements_by_xpath("//a[contains(text(), '(Force)')]")[0].click()

P.S. You also might need to wait until events number decreased by 1 after each click in case events removes too slow... or apply another approach:

driver.get(alarmurl)
# get initial events number
elems_count = len(driver.find_elements_by_xpath("//a[contains(text(), '(Force)')]"))

# execute click() for each event. Starting from the last one
for index in range(elems_count):
    driver.find_elements_by_xpath("//a[contains(text(), '(Force)')]")[elems_count - index - 1].click()