简体   繁体   中英

Selenium Webdriver with Python - NoSuchWindowException after using frame_to_be_available_and_switch_to_it()

I'm trying to work with Selenium Webdriver with Python, automating the Chrome browser.

In re-optimising my code, I'm trying to get rid of any time.sleep() commands and using implicit and explicit waits when possible.

The part I'm stuck on is an iframe / modal dialog - after switching to it I still need to wait for the modal dialog to load before I can interact with elements without errors.

Code that works:

driver.find_element(By.ID, "process").click()   # Process form button - creates modal dialog
time.sleep(2)                                   # Delay to wait for the frame to load
driver.switch_to.frame("acsframe")              # acsframe is the ID of the modal dialog
driver.find_element(By.CSS_SELECTOR, r'input.btn.btn-warning').click() # Cancel button

Code that I'm trying to get to work:

driver.find_element(By.ID, "process").click() # Process form button
WebDriverWait(driver, 5).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "acsframe")))
WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.CSS_SELECTOR, r'input.btn.btn-warning')))
driver.find_element(By.CSS_SELECTOR, r'input.btn.btn-warning').click() # Cancel button

Error Message:

NoSuchWindowException                     Traceback (most recent call last)
<ipython-input-24-acf8921ff08a> in <module>
      2 WebDriverWait(driver, 5).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "acsframe")))
----> 3 WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.CSS_SELECTOR, r'input.btn.btn-warning')))
      4 driver.find_element(By.CSS_SELECTOR, r'input.btn.btn-warning').click()

I don't understand how/why I would be getting an error message here. I switch to the frame on line 2, and line 3 works about 1 time in 10, but otherwise throws an error. I know the element locator is right because it worked in the first example. If time.sleep() worked, why wouldn't this work?

I've tried changing between XPATH and CSS Selector for locating the elements and it's the same result. There aren't any IDs for the buttons.

Update: This code also works:

driver.find_element(By.ID, "process").click() # Process form button
time.sleep(2)
WebDriverWait(driver, 5).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "acsframe")))
WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.CSS_SELECTOR, r'input.btn.btn-warning')))
driver.find_element(By.CSS_SELECTOR, r'input.btn.btn-warning').click()

So it seems that a delay before waiting for the frame fixes it - but isn't that the entire purpose of the command to wait for the frame to be available? I still want a way to get this to work without time.sleep() .

Screenshot of the relevant HTML

As the element is within an <iframe> so you have to:

  • Induce WebDriverWait for the desired frame to be available and switch to it .

  • Induce WebDriverWait for the desired element to be clickable .

  • You can use the following Locator Strategies :

     driver.find_element(By.ID, "process").click() # Process form button WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "acsframe"))) WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, r'input.btn.btn-warning'))).click()

Reference

You can find a couple of relevant discussions in:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM