jQuery/JavaScript: accesarea conținutului unui iframe (Programare, Javascript, Jquery, Iframe, Aceeași Politică De Origine)

rz. a intrebat.

Aș dori să manipulez HTML-ul din interiorul unui iframe folosind jQuery.

Am crezut că voi putea face acest lucru prin setarea contextului funcției jQuery să fie documentul iframe-ului, ceva de genul:

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

Cu toate acestea, acest lucru nu pare să funcționeze. Un pic de inspecție îmi arată că variabilele din frames['nameOfMyIframe'] sunt undefined dacă nu aștept puțin timp până se încarcă iframe-ul. Cu toate acestea, atunci când iframe-ul se încarcă, variabilele nu sunt accesibile (obțin permission denied-erori de tip).

Știe cineva o soluție pentru a rezolva acest lucru?

Comentarii

  • Ce conține iFrame-ul – src-ul său este setat pe un alt domeniu? –  > Por James.
  • dacă este un alt domeniu, mai există o modalitate de a accesa conținutul său sau de a înregistra un eveniment?  > Por adardesign.
  • 35

  • Nu, pentru că ar fi vorba de scripting cross-site, care este interzis din motive de securitate. Soluția mea a fost să folosesc un proxy: să alimentez HTML-ul din IFRAME textual prin propriul meu site, astfel încât să nu mai fie vorba de cross-site din perspectiva browserului. –  > Por reinierpost.
  • Este mai mult cross-browser să folosești .contentWindow.document decât .document pe iframe element. Voi sugera modificarea de mai sus. –  > Por Alan H..
  • o modalitate este extensiile Chrome –  > Por Muhammad Umer.
14 răspunsuri
Onur Bebin

Cred că ceea ce faci tu este supus la aceeași politică de origine. Acesta ar trebui să fie motivul pentru care primiți tipul de permisiune refuzată erori.

Comentarii

  • @Pacerier Cel mai bun pariu este de a proxy conținutul iframe-ului pe site-ul dvs., dacă puteți… –  > Por Tracker1.
  • @Tracker1: Poți sugera vreun cadru/api/model de proiectare pentru implementarea acestei soluții proxy. Vreo legătură cu exemple sau tutoriale etc.? Am încercat să caut, dar nu am putut găsi nimic. –  > Por Umer Hayat.
  • În acest caz, el se referă la utilizarea serverului http care servește pagina domeniului dvs. ca proxy – solicitați conținutul de pe site-ul terț și transmiteți-l mai departe în răspunsul http către client. După cum probabil puteți ghici, acest lucru are un impact rapid asupra capacității de reacție a site-ului dumneavoastră, deoarece cererile care înainte erau paralele sunt în schimb executate în serie, serverul dumneavoastră fiind un potențial gât de gâtul de la intrare. –  > Por rutherford.
  • @Pacerier Potențial, oricare dintre metodele din răspunsul acceptat aici: stackoverflow.com/questions/3076414/… sau altele (cum ar fi utilizarea propriului domeniu ca proxy), în funcție de ceea ce doriți să obțineți. –  > Por Mark Amery.
  • Pentru înregistrare, tocmai am configurat ceva similar : dacă nu doriți ca rezultatul să fie incredibil de lent, configurați-vă serverul web pentru a redirecționa direct solicitările de active (CSS/JS/imagini) către site-ul web original, astfel încât proxy-ul dvs. să gestioneze doar solicitările HTML. Chiar acum navighez pe un site îndepărtat sub localhost și este absolut transparent 🙂 –  > Por neemzy.
Yasir Laghari

În cazul în care <iframe> este din același domeniu, elementele sunt ușor accesibile ca

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

Referință

Comentarii

    163

  • Să știi despre politica de aceeași origine este grozav, dar acesta este răspunsul care face ceea ce a vrut OP. De ce a fost ales celălalt răspuns ca fiind cel corect? –  > Por Jason Swett.
  • Trebuie să folosiți un proxy pentru a obține HTML-ul în originea dvs. De exemplu, johnchapman.name/… –  > Por mhenry1384.
  • @JasonSwett, presupun că problema lui OP este într-adevăr problema lui same origin policy, caz în care acest răspuns nu este o soluție pentru el. –  > Por ANeves crede că SE este rău.
  • @fizzbuzz Atunci obțineți IFrame-ul în același mod în care ați obține orice alt conținut fără id cu jQuery: selectați tag-ul <IFrame> corespunzător cu CSS, folosind nume de clase și valori de atribute pentru a restrânge dacă este necesar. –  > Por Auspex.
  • Nu există o metodă numită contents pentru iframe. –  > Por Geeky Guy.
davryusha

Ați putea folosi .contents() metoda de jQuery.

La .contents() poate fi folosită și pentru a obține documentul de conținut al unui iframe, dacă iframe-ul se află pe același domeniu ca și pagina principală.

$(document).ready(function(){
    $('#frameID').load(function(){
        $('#frameID').contents().find('body').html('Hey, i`ve changed content of <body>! Yay!!!');
    });
});

Comentarii

  • am nevoie să obțin conținutul cadrului i frame nu să setez corpul ….. Atunci când fac cele de mai sus, nu funcționează, returnând întotdeauna un corp gol.  > Por George Hanna.
  • @DarkoZ Hm, de fapt, acest răspuns a venit primul, deci, dacă este cazul, celălalt răspuns a fost copia –  > Por michaelpri.
  • @DarkoZ: lăsând comentariul original nu m-a făcut să te fac de rușine, dar am pierdut vreo 30 de secunde încercând să înțeleg o non-problemă 🙂 Așa că eliminarea întregii discuții despre un răspuns plagiator ar fi cel mai bine. –  > Por Dan Dăscălescu.
  • comentarii eliminate pentru a preveni confuzia. scuze. –  > Por Darko Z.
basysmith

Dacă src-ul iframe este de pe un alt domeniu, tot poți face asta. Trebuie să citiți pagina externă în PHP și să o transmiteți ca ecou din domeniul dvs. Așa:

iframe_page.php

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

    $domain = file_get_contents($URL);

    echo $domain;
?>

Apoi ceva de genul acesta:

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>

Exemplul de mai sus este un exemplu despre cum se poate edita o pagină externă prin intermediul unui iframe fără acces refuzat etc…

Comentarii

  • Desigur, deoarece serverul dvs. primește pagina la distanță, nu browserul utilizatorului, nu vor fi trimise cookie-uri către pagina la distanță. YMMV. –  > Por Mark Fowler.
  • @Mark: Puteți trimite cu ușurință cookie-uri, date postate, anteturi HTTP și altele dacă implementați extensia curl. php.net/manual/en/book.curl.php –  > Por geon.
  • @geon: dar browserul nu va trimite cookie-uri pentru domeniul străin către scriptul dvs. PHP –  > Por ysth.
  • @basysmith Fiți atenți: există un motiv pentru care same origin policy există, iar propunerea acestui răspuns nu este imună la el. –  > Por ANeves crede că SE este rău.
  • este ilegal în vreun fel să faci asta? –  > Por Tallboy.
utilizator

Utilizați

iframe.contentWindow.document

în loc de

iframe.contentDocument

Comentarii

  • Un răspuns excelent. Acest lucru funcționează pentru iFrame în alte domenii. Am încercat acest lucru în consolă pe Safari și Firefox. –  > Por Aneil Mallavarapu.
  • Cred că va funcționa doar pentru alte domenii dacă o faceți din consolă. Dintr-un script, accesul nu va fi permis. –  > Por yincrash.
  • Acesta ar trebui să fie răspunsul acceptat. Mi-a salvat viața și funcționează atunci când iframe-ul este de la un alt domeniu; deși, așa cum am menționat, numai în consolă. –  > Por silkfire.
  • pentru mine iframe.contentWindow.document nu funcționează întotdeauna. și când nu funcționează am descoperit că $(elem).contents().get(0) funcționează – –  > Por elewinso.
  • puteți alege „documentul rădăcină” în consola browserului. Atunci când selectați „top” nu va funcționa, ca un acces cross-origin. Dacă alegeți să accesați în numele documentului iframe, bineînțeles că vă va da acces. Doar pentru că nu sunteți un browser, ci proprietarul browserului. –  > Por Sergei Kovalenko.
zupa

Găsesc acest mod mai curat:

var $iframe = $("#iframeID").contents();
$iframe.find('selector');

Comentarii

  • M-a salvat – o luasem razna, folosind „$(„#iframe”).contents().find()” nu funcționa din anumite motive… același lucru pe două linii a făcut-o. Nu știu de ce, dar funcționează. –  > Por neminem.
Andreas Grech

Trebuie să atașați un eveniment la onload handler-ul unui iframe și să executați js-ul acolo, astfel încât să vă asigurați că iframe-ul a terminat de încărcat înainte de a-l accesa.

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

Cele de mai sus vor rezolva problema „not-yet-loaded”, dar în ceea ce privește permisiunile, dacă încarci în iframe o pagină care provine dintr-un alt domeniu, nu o vei putea accesa din cauza restricțiilor de securitate.

Comentarii

  • aceasta este o idee bună, de fapt am încercat-o chiar așa cum mi-ai răspuns. Cu toate acestea, nu rezolvă problema permisiunii refuzate (rezolvă însă problema faptului că trebuie să aștept înainte de a începe să accesez chestiile din iframe)  > Por rz..
  • de fapt… nu mai contează, se pare că așteptarea este în continuare necesară chiar și atunci când se face acest lucru. –  > Por rz..
  • Funcția ready funcționează. Cu toate acestea, se pare că nu așteaptă ca conținutul iframe-ului să se termine de încărcat, ci doar documentul părinte, chiar și atunci când este invocată pe conținutul iframe-ului. Îmi imaginez că este și din cauza aceleiași politici de origine. –  > Por rz..
  • Câteva note cu privire la acest cod: ar trebui să folosiți iframe.contentDocument în loc de .document și ar trebui să folosiți .load() în loc de .ready() pentru a evita așteptarea. (Nu este perfect, dar este mai bine) –  > Por Rodrigo Queiro.
B.Asselin

Puteți utiliza window.postMessage pentru a apela o funcție între pagină și iframe-ul său (cross domain sau nu).

Documentație

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 + '
' + 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 + '
' + 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>

Evgeny Karpov

Prefer să folosesc altă variantă pentru accesare. de la părinte puteți avea acces la o variabilă din iframe-ul copil.$ este și ea o variabilă și poți primi acces la ea doar apelândwindow.iframe_id.$

De exemplu, window.view.$('div').hide() – ascundeți toate div-urile din iframe cu id ‘view’

Dar, nu funcționează în FF. Pentru o mai bună compatibilitate, ar trebui să utilizați

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

Khb

Ați încercat varianta clasică, așteptând ca încărcarea să se finalizeze folosind funcția ready încorporată de jQuery?

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

K

Comentarii

  • Da. Funcția ready începe să se execute când se încarcă cadrul principal – nu când se încarcă iframe-ul. Totuși, așteptarea pare să fie o mică parte a problemei. Cred că are legătură cu securitatea între domenii. –  > Por rz..
Zisu

Am creat un cod de probă . Acum puteți înțelege cu ușurință că din alt domeniu nu puteți accesa conținutul iframe-ului .. Același domeniu putem accesa conținutul iframe-ului

Vă împărtășesc codul meu , Vă rugăm să rulați acest codverificați consola . Am tipărit src-ul imaginii în consolă. Există patru iframe , două iframe provenind din același domeniu & alte două din alt domeniu (terță parte) .Puteți vedea două imagini src( https://www.google.com/logos/doodles/2015/googles-new-logo-5078286822539264.3-hp2x.gif

și

https://www.google.com/logos/doodles/2015/arbor-day-2015-brazil-5154560611975168-hp2x.gif ) la consolă și, de asemenea, pot vedea două erori de permisiune (2Error: Permisiune refuzată pentru accesarea proprietății „document

…irstChild)},contents:function(a){return m.nodeName(a, „iframe”)?a.contentDocument….

) care provine de la iframe de la o terță parte.

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

Dominique Fortin

Pentru și mai multă robustețe:

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

și

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

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

Jeff Davis

Am ajuns aici căutând să obțin conținutul unui iframe fără jquery, așa că pentru oricine altcineva care caută asta, este doar acest lucru:

document.querySelector('iframe[name=iframename]').contentDocument

Ahsan Horani

Această soluție funcționează la fel ca iFrame. Am creat un script PHP care poate obține tot conținutul de pe celălalt site web, iar partea cea mai importantă este că puteți aplica cu ușurință jQuery personalizat la acel conținut extern. Vă rugăm să consultați următorul script care poate obține tot conținutul de pe celălalt site web și apoi puteți aplica și jQuery/JS personalizat. Acest conținut poate fi utilizat oriunde, în interiorul oricărui element sau în orice pagină.

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

Comentarii

  • Cum ar funcționa acest lucru? Dacă adăugați șirul $customJS la $content, nu veți avea elementul de script DUPĂ tag-ul html de închidere (al domeniului extern)? –  > Por ultrageek.