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?


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 .


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


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!!!');
    });
});

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 ...


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');

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

Ó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.


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>

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.$


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


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>

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

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;
}

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();
  ...
}
...
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.