47

Edit: New title. What I'm looking for is a document.querySelector for elements inside an iframe.

I've done quite a bit of Googling for an answer and finally I'm stumped.

I'm trying to query inside an iframe. I'm building string selectors to be used in Selenium and usually I just inspect the element with Firebug, and use document.querySelectorAll("theStringIBuid");

But it doesn't work with elements inside iframes. I've tried all of the below to get an element "radiobutton1" inside the "page-iframe" iframe.

var elem1 = ".page-iframe";
console.log(elem1);
var elem2 = ".radiobutton1";
console.log(elem2);
document.querySelectorAll(elem1+elem2+"");

document.querySelectorAll('.page-iframe').contentWindow.document.body.querySelectorAll('.radiobutton1')
document.getElementById('.page-iframe').contentWindow.document.body.innerHTML;

[].forEach.call( document.querySelectorAll('.page-iframe'), 
function  fn(elem){ 
console.log(elem.contentWindow.document.body.querySelectorAll('.radiobutton1')); });

var contentWindow = document.getElementById('.page-iframe').contentWindow 
var contentWindow = document.querySelectorAll('.page-iframe') 
var contentWindow = document.querySelectorAll('.page-iframe')[0].contentWindow

Thanks-

BoltClock
  • 630,065
  • 150
  • 1,295
  • 1,284
snug
  • 471
  • 1
  • 4
  • 4
  • Are you maybe running the script before the iframe is done loading? What do you get if you console.log the contentWindow? – Spokey Oct 29 '14 at 12:38
  • If you're using selenium you will need to call switchTo().frame("id of frame") then run your code. – bcar Oct 29 '14 at 12:52
  • Well I've been working on this for two hours now so I think the page is done loading :) – snug Oct 30 '14 at 08:31
  • And I'm not using Selenium to write the query, I'm trying to write the query in Firebug console. Any idea how to write a console query to access elements inside an iframe? – snug Oct 30 '14 at 08:34

4 Answers4

54

simple es6 adapted from h3manth:

document.querySelectorAll('iframe').forEach( item =>
    console.log(item.contentWindow.document.body.querySelectorAll('a'))
)
cregox
  • 15,711
  • 14
  • 77
  • 111
  • 2
    Uncaught SecurityError: Blocked a frame with origin "https://xxx.xxx.xx" from accessing a frame with origin "https://www.google.com". Protocols, domains, and ports must match.", source: https://xxx.xxx.xx/#!/ (1) – Iman Marashi Jan 05 '20 at 23:19
  • are you sure the domain in and out the iframe are the same? – cregox Jan 06 '20 at 07:54
  • 1
    I don't know about Selenium, but with puppeteer you can pass "--disable-web-security" in the launch args and access cross-origin frames. – LandonC May 26 '20 at 21:23
  • 1
    Just sharing an working example with typescript: document.getElementById("...")['contentWindow'].document.querySelectorAll("..."). Ty! – Gauss Jun 04 '20 at 02:13
28

if the original page's url isn't at the same domain with the iframe content, the javascript will treat the iframe as a black box, meaning it will not see anything inside it.

Aero Wang
  • 6,227
  • 9
  • 35
  • 70
  • 1
    That is right. See this question: https://stackoverflow.com/questions/25098021/securityerror-blocked-a-frame-with-origin-from-accessing-a-cross-origin-frame – Elias Zamaria Mar 29 '18 at 06:06
3

You can do this: document.querySelector("iframe").contentWindow.document.querySelector("button") https://m.youtube.com/watch?v=-mNp3-UX9Qc

0

Here's a snippet for diving into same-origin frames (ie-compatible ES5):

function findInFramesRec(selector, doc) {
  var hit = doc.querySelector(selector);
  if (hit) return hit;
  var frames = Array.prototype.slice.call(doc.frames);
  for(var i = 0; (i < frames.length) &&   !hit   ; i++) {
    try {
      if (!frames[i] || !frames[i].document) continue;
      hit = findInFramesRec(selector, frames[i].document);
    } catch(e) {}
  }
  return hit;
}

This dives into both frameset frames and iframes alike. It may even survive (though not enter) cross origin frames.

LOAS
  • 6,872
  • 2
  • 25
  • 24