jQuery / JavaScript: acessando o conteúdo de um iframe

792

Eu gostaria de manipular o HTML dentro de um iframe usando jQuery.

Eu pensei que seria capaz de fazer isso, definindo o contexto da função jQuery como o documento do iframe, algo como:

$(function(){ //document ready
    $('some selector', frames['nameOfMyIframe'].document).doStuff()
});

No entanto, isso não parece funcionar. Um pouco de inspeção mostra que as variáveis frames['nameOfMyIframe']são, a undefinedmenos que eu espere um pouco até o iframe carregar. No entanto, quando o iframe é carregado, as variáveis ​​não estão acessíveis (eu recebo permission deniederros de tipo).

Alguém sabe de uma solução alternativa para isso?

rz.
fonte
3
O que o iFrame contém - seu src está definido para outro domínio?
James
se é um outro domínio, há ainda uma maneira de acessar seu conteúdo ou registar-se um evento
adardesign
34
Não, porque isso seria script entre sites, o que é proibido por razões de segurança. Minha solução foi usar um proxy: alimente o HTML no IFRAME literalmente através do meu próprio site, para que ele não seja mais cross-site da perspectiva do navegador.
reinierpost
É mais para vários navegadores usar do .contentWindow.documentque .documentsobre o iframeelemento. Vou sugerir a alteração acima.
Alan H.
1
é uma maneira de extensões do Chrome
Muhammad Umer

Respostas:

384

Acho que o que você está fazendo está sujeito à mesma política de origem . Esse deve ser o motivo pelo qual você está recebendo erros de tipo de permissão negada .

Onur Bebin
fonte
6
@Pacerier A melhor aposta é fazer proxy do conteúdo do iframe no seu site, se você puder ... #
314
10
@ Tracker1: Você pode sugerir qualquer estrutura / API / padrão de design para implementar esta solução de proxy. Algum link para exemplo ou tutorial etc? Eu tentei pesquisar, mas não consegui encontrar nenhum.
Umer Hayat
3
Nesse caso, ele quer dizer usar o servidor http que está servindo a página do seu domínio como proxy - solicitar o conteúdo do site de terceiros e encaminhá-lo na resposta http ao cliente. Como você provavelmente pode adivinhar, isso afeta rapidamente a capacidade de resposta do seu site, pois solicitações anteriormente paralelas são executadas em série com o servidor como um gargalo em potencial.
Rutherford #
1
@Pacerier Potencialmente, qualquer um dos métodos na resposta aceita aqui: stackoverflow.com/questions/3076414/… ou outros (como usar seu próprio domínio como proxy), dependendo do que você deseja alcançar.
Mark Amery
4
Para o registro, eu apenas configurei algo semelhante: se você não quiser que o resultado seja incrivelmente lento, basta configurar seu servidor da Web para redirecionar diretamente as solicitações de ativos (CSS / JS / images) para o site original, portanto, seu proxy gerencia apenas solicitações HTML. Eu estou navegando em um local distante sob localhost agora e é absolutamente transparente :)
neemzy
985

Se <iframe>for do mesmo domínio, os elementos são facilmente acessíveis como

$("#iFrame").contents().find("#someDiv").removeClass("hidden");

Referência

Yasir Laghari
fonte
157
Conhecer a mesma política de origem é ótimo, mas esta é a resposta que faz o que o OP queria. Por que a outra resposta foi escolhida como a correta?
precisa
2
Você precisa usar um proxy para obter o HTML em sua origem. Por exemplo, johnchapman.name/…
mhenry1384
7
@ JasonSwett, meu palpite é que o problema do OP é realmente o same origin policy, nesse caso, essa resposta não é uma solução para ele.
ANRS #
3
@fizzbuzz Então você obtém o IFrame da mesma maneira que qualquer outro conteúdo sem ID com o jQuery: você seleciona a tag <IFrame> apropriada com CSS, usando nomes de classe e valores de atributo para reduzi-lo, se necessário.
Auspex #
2
Não existe um método chamado conteúdo para o iframe.
Renan
88

Você poderia usar o .contents()método jQuery.

O .contents()método também pode ser usado para obter o documento de conteúdo de um iframe, se o iframe estiver no mesmo domínio da página principal.

$(document).ready(function(){
    $('#frameID').load(function(){
        $('#frameID').contents().find('body').html('Hey, i`ve changed content of <body>! Yay!!!');
    });
});
davryusha
fonte
2
eu preciso para obter o conteúdo do quadro i não para definir o corpo ..... Quando eu fizer o acima não funciona sempre retornam corpo vazio
George Hanna
3
@DarkoZ Hum, na verdade, essa resposta veio primeiro, por isso, se qualquer coisa, a outra resposta era a cópia
michaelpri
@DarkoZ: deixar o comentário original não me fez envergonhar você, mas perdi 30 segundos tentando entender um não-problema :) Portanto, remover a discussão toda sobre uma resposta plágio pode ser o melhor.
Dan Dascalescu
comentários removidos para evitar confusão. desculpas.
Darko Z
43

Se o iframe src for de outro domínio, você ainda poderá fazê-lo. Você precisa ler a página externa no PHP e repeti-la em seu domínio. Como isso:

iframe_page.php

<?php
    $URL = "http://external.com";

    $domain = file_get_contents($URL);

    echo $domain;
?>

Então algo como isto:

display_page.html

<html>
<head>
  <title>Test</title>
 </head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>

<script>

$(document).ready(function(){   
    cleanit = setInterval ( "cleaning()", 500 );
});

function cleaning(){
    if($('#frametest').contents().find('.selector').html() == "somthing"){
        clearInterval(cleanit);
        $('#selector').contents().find('.Link').html('ideate tech');
    }
}

</script>

<body>
<iframe name="frametest" id="frametest" src="http://yourdomain.com/iframe_page.php" ></iframe>
</body>
</html>

O exemplo acima é um exemplo de como editar uma página externa através de um iframe sem o acesso negado, etc ...

ferreiro
fonte
12
Obviamente, como o servidor está recebendo a página remota e não o navegador do usuário, nenhum cookie será enviado para a página remota. YMMV.
Mark Fowler
1
@ Mark: Você pode facilmente enviar cookies, dados publicados, cabeçalhos HTTP e outros enfeites se você implementá-lo com a extensão curl. php.net/manual/en/book.curl.php
Geon
2
@geon: mas o navegador não envia cookies para o domínio estrangeiro para o seu script PHP #
20-11
6
@basysmith Esteja atento: existe uma razão para a existência same origin policy, e a proposta desta resposta não é imune a ela.
ANRS
1
é ilegal de alguma forma fazer isso?
Tallboy
32

Acho esse caminho mais limpo:

var $iframe = $("#iframeID").contents();
$iframe.find('selector');
zupa
fonte
Salvei minha bunda - eu estava ficando louco, usando "$ (" # iframe "). Contents (). Find ()" não estava funcionando por algum motivo ... a mesma coisa em duas linhas. Não sei por que, mas funciona.
NEMEMEM
30

Usar

iframe.contentWindow.document

ao invés de

iframe.contentDocument
do utilizador
fonte
Ótima resposta. Isso funciona para iFrames em outros domínios. Eu tentei isso no console do Safari e Firefox.
Aneil Mallavarapu
12
Acredito que só funcionará para outros domínios se você estiver usando o console. A partir de um script, o acesso não será permitido.
yincrash
Essa deve ser a resposta aceita. Salvei minha vida e funciona quando o iframe é de um domínio diferente; embora como mencionado, apenas no console.
silkfire
para mim, iframe.contentWindow.document nem sempre funciona. . e quando ele não achei que US $ .contents (elem) () get (0) faz
elewinso
você pode escolher o "documento raiz" no console do navegador. Quando você seleciona "top", ele não funciona, como um acesso de origem cruzada. Se você optar por acessar em nome do documento iframe, é claro que ele lhe dará acesso. Só porque você não é um navegador, mas o proprietário do navegador.
Sergei Kovalenko
26

Você precisa anexar um evento ao manipulador de onload de um iframe e executar os js nele, para garantir que o iframe tenha terminado o carregamento antes de acessá-lo.

$().ready(function () {
    $("#iframeID").ready(function () { //The function below executes once the iframe has finished loading
        $('some selector', frames['nameOfMyIframe'].document).doStuff();
    });
};

O procedimento acima resolverá o problema 'ainda não carregado', mas no que diz respeito às permissões, se você estiver carregando uma página no iframe de outro domínio, não poderá acessá-la devido a restrições de segurança.

Andreas Grech
fonte
essa é uma boa ideia, na verdade eu estava tentando exatamente como você respondeu. No entanto, ele não funciona com a permissão negada (aborda o fato de eu ter que esperar antes de começar a acessar o material iframe)
rz.
na verdade ... deixa pra lá, parece que a espera ainda é necessária, mesmo ao fazer isso.
rz.
A função ready funciona. No entanto, parece que ele não espera o conteúdo do iframe terminar de carregar - apenas para o documento pai, mesmo quando invocado no conteúdo do próprio iframe. Imagino que seja também por causa da mesma política de origem.
rz.
3
Algumas notas sobre este código: você deve usar iframe.contentDocument em vez de .document e usar .load () em vez de .ready () para evitar a espera. (Não é perfeito, mas melhor)
Rodrigo Queiró
21

Você pode usar window.postMessage para chamar uma função entre a página e seu iframe (domínio cruzado ou não).

Documentação

page.html

<!DOCTYPE html>
<html>
<head>
    <title>Page with an iframe</title>
    <meta charset="UTF-8" />
    <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script>
    var Page = {
        id:'page',
        variable:'This is the page.'
    };

    $(window).on('message', function(e) {
        var event = e.originalEvent;
        if(window.console) {
            console.log(event);
        }
        alert(event.origin + '\n' + event.data);
    });
    function iframeReady(iframe) {
        if(iframe.contentWindow.postMessage) {
            iframe.contentWindow.postMessage('Hello ' + Page.id, '*');
        }
    }
    </script>
</head>
<body>
    <h1>Page with an iframe</h1>
    <iframe src="iframe.html" onload="iframeReady(this);"></iframe>
</body>
</html>

iframe.html

<!DOCTYPE html>
<html>
<head>
    <title>iframe</title>
    <meta charset="UTF-8" />
    <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script>
    var Page = {
        id:'iframe',
        variable:'The iframe.'
    };

    $(window).on('message', function(e) {
        var event = e.originalEvent;
        if(window.console) {
            console.log(event);
        }
        alert(event.origin + '\n' + event.data);
    });
    $(window).on('load', function() {
        if(window.parent.postMessage) {
            window.parent.postMessage('Hello ' + Page.id, '*');
        }
    });
    </script>
</head>
<body>
    <h1>iframe</h1>
    <p>It's the iframe.</p>
</body>
</html>
B.Asselin
fonte
4

Eu prefiro usar outra variante para acessar. Do pai, você pode ter acesso à variável no iframe filho. $também é uma variável e você pode receber acesso apenas à sua chamada window.iframe_id.$

Por exemplo, window.view.$('div').hide()- oculte todas as divs no iframe com o ID 'view'

Mas, não funciona no FF. Para melhor compatibilidade, você deve usar

$('#iframe_id')[0].contentWindow.$

Evgeny Karpov
fonte
2

Você já experimentou o clássico, aguardando a conclusão da carga, usando a função integrada do jQuery?

$(document).ready(function() {
    $('some selector', frames['nameOfMyIframe'].document).doStuff()
} );

K

Khb
fonte
2
Sim. A função ready começa a executar quando o quadro principal é carregado - não quando o iframe é carregado. A espera parece ser uma pequena parte do problema. Eu acho que tem a ver com segurança entre domínios.
rz.
2

Eu crio um código de exemplo. Agora você pode entender facilmente de diferentes domínios, não pode acessar o conteúdo do iframe. Mesmo domínio, podemos acessar o conteúdo do iframe

Partilho o meu código. Por favor, execute este código, verifique a consola. Eu imprimo a imagem src no console. Existem quatro iframe, dois iframe provenientes do mesmo domínio e outros dois de outro domínio (terceiros). Você pode ver duas imagens src ( https://www.google.com/logos/doodles/2015/googles-new-logo -5078286822539264.3-hp2x.gif

e

https://www.google.com/logos/doodles/2015/arbor-day-2015-brazil-5154560611975168-hp2x.gif ) no console e também pode ver dois erros de permissão (2 Erro: permissão negada para acessar o documento da propriedade) "

... irstChild)}, conteúdo: function (a) {return m.nodeName (a, "iframe")? a.contentDocument ...

) proveniente de iframe de terceiros.

<body id="page-top" data-spy="scroll" data-target=".navbar-fixed-top">
<p>iframe from same domain</p>
  <iframe frameborder="0" scrolling="no" width="500" height="500"
   src="iframe.html" name="imgbox" class="iView">

</iframe>
<p>iframe from same domain</p>
<iframe frameborder="0" scrolling="no" width="500" height="500"
   src="iframe2.html" name="imgbox" class="iView1">

</iframe>
<p>iframe from different  domain</p>
 <iframe frameborder="0" scrolling="no" width="500" height="500"
   src="https://www.google.com/logos/doodles/2015/googles-new-logo-5078286822539264.3-hp2x.gif" name="imgbox" class="iView2">

</iframe>

<p>iframe from different  domain</p>
 <iframe frameborder="0" scrolling="no" width="500" height="500"
   src="http://d1rmo5dfr7fx8e.cloudfront.net/" name="imgbox" class="iView3">

</iframe>

<script type='text/javascript'>


$(document).ready(function(){
    setTimeout(function(){


        var src = $('.iView').contents().find(".shrinkToFit").attr('src');
    console.log(src);
         }, 2000);


    setTimeout(function(){


        var src = $('.iView1').contents().find(".shrinkToFit").attr('src');
    console.log(src);
         }, 3000);


    setTimeout(function(){


        var src = $('.iView2').contents().find(".shrinkToFit").attr('src');
    console.log(src);
         }, 3000);

         setTimeout(function(){


        var src = $('.iView3').contents().find("img").attr('src');
    console.log(src);
         }, 3000);


    })


</script>
</body>
Zisu
fonte
1

Acabei aqui procurando obter o conteúdo de um iframe sem jquery; portanto, para qualquer pessoa que procure por isso, é apenas isso:

document.querySelector('iframe[name=iframename]').contentDocument
Jeff Davis
fonte
1

Esta solução funciona da mesma forma que o iFrame. Eu criei um script PHP que pode obter todo o conteúdo de outro site, e a parte mais importante é que você pode aplicar facilmente seu jQuery personalizado a esse conteúdo externo. Consulte o seguinte script que pode obter todo o conteúdo do outro site e, em seguida, você pode aplicar o seu jQuery / JS personalizado. Este conteúdo pode ser usado em qualquer lugar, dentro de qualquer elemento ou página.

<div id='myframe'>

  <?php 
   /* 
    Use below function to display final HTML inside this div
   */

   //Display Frame
   echo displayFrame(); 
  ?>

</div>

<?php

/* 
  Function to display frame from another domain 
*/

function displayFrame()
{
  $webUrl = 'http://[external-web-domain.com]/';

  //Get HTML from the URL
  $content = file_get_contents($webUrl);

  //Add custom JS to returned HTML content
  $customJS = "
  <script>

      /* Here I am writing a sample jQuery to hide the navigation menu
         You can write your own jQuery for this content
      */
    //Hide Navigation bar
    jQuery(\".navbar.navbar-default\").hide();

  </script>";

  //Append Custom JS with HTML
  $html = $content . $customJS;

  //Return customized HTML
  return $html;
}
Ahsan Horani
fonte
0

Para ainda mais robustez:

function getIframeWindow(iframe_object) {
  var doc;

  if (iframe_object.contentWindow) {
    return iframe_object.contentWindow;
  }

  if (iframe_object.window) {
    return iframe_object.window;
  } 

  if (!doc && iframe_object.contentDocument) {
    doc = iframe_object.contentDocument;
  } 

  if (!doc && iframe_object.document) {
    doc = iframe_object.document;
  }

  if (doc && doc.defaultView) {
   return doc.defaultView;
  }

  if (doc && doc.parentWindow) {
    return doc.parentWindow;
  }

  return undefined;
}

e

...
var frame_win = getIframeWindow( frames['nameOfMyIframe'] );

if (frame_win) {
  $(frame_win.contentDocument || frame_win.document).find('some selector').doStuff();
  ...
}
...
Dominique Fortin
fonte