Home > OS >  Selenium Python: Trying to get an iframe within an iframe
Selenium Python: Trying to get an iframe within an iframe

Time:12-04

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):

enter image description here

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:

  • Related