Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
291 views
in Technique[技术] by (71.8m points)

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

question from:https://stackoverflow.com/questions/65626913/selenium-webdriver-with-python-nosuchwindowexception-after-using-frame-to-be-a

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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:


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...