7

I am trying to select an element which resides inside an iframe and probably in other iframes.

Is it somehow possible to select an element within some (sub-)iframe in (python)selenium without selecting the iframes before? Is there a way to 'loop' over every iframe somehow and to check where to find my element...?

And how to do that in the case elements and html stuff and iframes might just about being loaded...?

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
Alex
  • 41,580
  • 88
  • 260
  • 469
  • It's possible with a JavaScript injection by using `querySelectorAll` recursively over each frame. However the script will be restricted by the same origin policy, which means that you'll only be able to do so with frames from the same domain as the main page. – Florent B. Dec 12 '17 at 10:46
  • Then I guess this is not an option for me. Thanks for the suggestion anyway... – Alex Dec 12 '17 at 10:47
  • If you are using Chrome, it should be possible to disable the same origin policy by launching the browser with the switch ` --disable-web-security`. – Florent B. Dec 12 '17 at 10:51
  • I wonder why this is so insanely complicated with selenium anyways. When you use the GUI you just 'click' on an element. And with selenium you have these impossible issues with frames... – Alex Dec 12 '17 at 10:52

2 Answers2

9

No, it is not possible to interact with any WebElement within an <iframe> through Selenium without switching to the respective iframe.

Reason :

When a page is loaded, Selenium's focus by default remains on the Top Window. The Top Window contains the other <iframes> and the framesets. So when we need to interact with a WebElement which is within an iframe we have to switch to the respective <iframe> through one of the below-mentioned methods :


Frame Switching Methods :

We can switch over to frames by 3 ways.

By Frame Name :

Name attribute of iframe through which we can switch to it.

Example:

driver.switch_to.frame("iframe_name")

By Frame ID :

ID attribute of iframe through which we can switch to it.

Example:

driver.switch_to.frame("iframe_id")

By Frame Index :

Suppose if there are 10 frames in the page, we can switch to the iframe by using the index.

Example:

driver.switch_to.frame(0)
driver.switch_to.frame(1)

Switching back to the Main Frame :

We can switch back to the main frame by using default_content() or parent_frame()

Example:

driver.switch_to.default_content()
driver.switch_to.parent_frame()

A Better Approach to Switch Frames:

A better way to switch frames will be to induce WebDriverWait for the availability of the intended frame with expected_conditions set to frame_to_be_available_and_switch_to_it as follows :

  • Through Frame ID:

     WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it(By.ID,"id_of_iframe"))
    
  • Through Frame Name:

     WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.NAME,"name_of_iframe")))
    
  • Through Frame Xpath:

     WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"xpath_of_iframe")))
    
  • Through Frame CSS:

     WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"css_of_iframe")))
    

Reference

You can find a relevant detailed discussion in:

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • But is there a reason that selenium has been constructed so inusable in the first place? Why don't people come up with a warpper around selenium so writing tests actually work...? – Alex Dec 12 '17 at 12:12
4

Writing your own recursive finder should be easy enough. Apologies, don't know python but in Java it would be something like:

public void findInAllFrames(WebElement e, String targetIdStr) {

    List<WebElement> l = e.findElements(By.tagName("iframe"));

    for(int inx=0; inx<l.size(); inx++) {
        List<WebElement> targets = l.get(inx).findElements(By.id(targetIdStr));
        if(targets.size()>0) {
            // Do something with your targets
        }

        findInAllFrames(l.get(inx), targetIdStr);
    }
}
MonkeyTester
  • 139
  • 5