I'm trying to switch the Selenium 'focus' to the contents inside of an iframe that's inside of another iframe. My selenium test below seems to work so far. However, there is another iframe within that iframe that I want to get- but I'm not sure now.
Here is the markup (second iframe highlighted):
This is my test so far (which works- just not sure how to get the second iframe within the first iframe):
import unittest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from .functional_test import FunctionalTest
class MyTest(FunctionalTest):
URL = '/datastory/my-datastory/'
@classmethod
def setUpClass(cls):
"""Set up method."""
super().setUpClass()
cls.URL = cls.format_url(cls.URL)
cls.login_user(cls)
def test_iframe(self):
container = self.browser.find_element_by_id('visual-31')
carousel = container.find_element_by_css_selector('.col-sm-12:nth-child(2) div.visual #classics-50-carousel')
wait = WebDriverWait(self.browser, 60)
wait.until(ec.visibility_of(carousel))
page_source = carousel.get_attribute("src");
self.assertEqual(
page_source,
'https://observablehq.com/embed/@ddsg/paramount-databyte-visuals?cells=classics50yrs'
)
# switch Selenium focus to the iframe
iframe = self.browser.switch_to.frame(carousel);
#NOW HOW DO I GET THE OTHER IFRAME??
# switch back
self.browser.switch_to.default_content()
CodePudding user response:
To switch within nested <iframe>
elements so you have to:
Induce WebDriverWait for the parent frame to be available and switch to it.
Induce WebDriverWait for the child frame to be available and switch to it.
Then
driver.find_element()
You can use either of the following Locator Strategies:
Using CSS_SELECTOR:
driver.get('https://xyz/datastory/my-datastory/') WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe.content[src='https://observablehq.com/embed/@ddsg/paramount-databyte-visuals?cells=classics50yrs']"))) WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe.content[src*='observableusercontent']"))) element = driver.find_element(By.ID, "id")
Using XPATH:
driver.get('https://xyz/datastory/my-datastory/') WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[@class='content' and @src='https://observablehq.com/embed/@ddsg/paramount-databyte-visuals?cells=classics50yrs']"))) WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[starts-with(@src, 'observableusercontent')]"))) element = driver.find_element(By.ID, "id")
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC
Reference
You can find a couple of relevant discussions in:
- Ways to deal with #document under iframe
- Switch to an iframe through Selenium and python
- selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element while trying to click Next button with selenium
- selenium in python : NoSuchElementException: Message: no such element: Unable to locate element