jQuery / JavaScript: Zugriff auf den Inhalt eines Iframes

792

Ich möchte den HTML-Code in einem Iframe mit jQuery bearbeiten.

Ich dachte, ich könnte dies tun, indem ich den Kontext der jQuery-Funktion als Dokument des Iframes einstelle, etwa:

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

Dies scheint jedoch nicht zu funktionieren. Ein bisschen Inspektion zeigt mir, dass die Variablen in frames['nameOfMyIframe']sind, es undefinedsei denn, ich warte eine Weile, bis der Iframe geladen ist. Wenn der Iframe geladen wird, ist jedoch nicht auf die Variablen zugegriffen (ich erhalte permission deniedFehler vom Typ Typ).

Kennt jemand eine Problemumgehung?

rz.
quelle
3
Was enthält der iFrame - ist sein src auf eine andere Domäne eingestellt?
James
Wenn es sich um eine andere Domain handelt, gibt es noch eine Möglichkeit, auf deren Inhalt zuzugreifen oder ein Ereignis zu registrieren
adardesign
34
Nein, denn das wäre Cross-Site-Scripting, was aus Sicherheitsgründen verboten ist. Meine Lösung bestand darin, einen Proxy zu verwenden: Führen Sie den HTML-Code im IFRAME wörtlich über meine eigene Site ein, damit er aus Sicht des Browsers nicht mehr standortübergreifend ist.
Reinierpost
Es ist mehr browserübergreifend .contentWindow.documentals .documentfür das iframeElement. Ich werde die Änderung oben vorschlagen.
Alan H.
1
Eine Möglichkeit sind Chrom-Erweiterungen
Muhammad Umer

Antworten:

384

Ich denke, was Sie tun, unterliegt der gleichen Herkunftsrichtlinie . Dies sollte der Grund sein, warum Sie Fehler erhalten , denen die Berechtigung verweigert wurde .

Onur Bebin
quelle
6
@ Pacerier Die beste Wette ist es, den Inhalt des Iframes auf Ihrer Website zu vertreten, wenn Sie können ...
Tracker1
10
@ Tracker1: Können Sie ein Framework / API / Design-Muster für die Implementierung dieser Proxy-Lösung vorschlagen? Irgendwelche Links zu Beispiel oder Tutorial usw.? Ich habe versucht zu suchen, konnte aber keine finden.
Umer Hayat
3
In diesem Fall bedeutet er, dass Sie den http-Server verwenden, der die Seite Ihrer Domain als Proxy bereitstellt. Fordern Sie den Inhalt von der Website eines Drittanbieters an und leiten Sie ihn in der http-Antwort an den Client weiter. Wie Sie wahrscheinlich erraten können, wirkt sich dies schnell auf die Reaktionsfähigkeit Ihrer Site aus, da zuvor parallele Anforderungen als potenzieller Engpass in Reihe mit Ihrem Server ausgeführt werden.
Rutherford
1
@Pacerier Möglicherweise eine der Methoden in der hier akzeptierten Antwort: stackoverflow.com/questions/3076414/… oder andere (z. B. die Verwendung Ihrer eigenen Domain als Proxy), je nachdem, was Sie erreichen möchten.
Mark Amery
4
Für die Aufzeichnung habe ich nur etwas Ähnliches eingerichtet: Wenn Sie nicht möchten, dass das Ergebnis unglaublich langsam ist, richten Sie Ihren Webserver so ein, dass Asset-Anforderungen (CSS / JS / Bilder) direkt an die ursprüngliche Website umgeleitet werden, also an Ihren Proxy verwaltet nur HTML-Anfragen. Ich surfe gerade auf einer entfernten Seite unter localhost und sie ist absolut transparent :)
neemzy
985

Wenn das <iframe>aus derselben Domäne stammt, sind die Elemente als leicht zugänglich

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

Referenz

Yasir Laghari
quelle
157
Es ist großartig, über dieselbe Herkunftspolitik Bescheid zu wissen, aber dies ist die Antwort, die das tut, was das OP wollte. Warum wurde die andere Antwort als die richtige ausgewählt?
Jason Swett
2
Sie müssen einen Proxy verwenden, um den HTML-Code in Ihrem Ursprung abzurufen. Zum Beispiel johnchapman.name/…
mhenry1384
7
@ JasonSwett, ich vermute, dass das Problem von OP tatsächlich das same origin policyist. In diesem Fall ist diese Antwort keine Lösung für ihn.
ANeves
3
@fizzbuzz Dann erhalten Sie den IFrame genauso wie andere Inhalte ohne ID mit jQuery: Sie wählen das entsprechende <IFrame> -Tag mit CSS aus und verwenden Klassennamen und Attributwerte, um ihn bei Bedarf einzugrenzen.
Auspex
2
Es gibt keine Methode namens Inhalt für den Iframe.
Renan
88

Sie können die .contents()Methode von jQuery verwenden.

Die .contents()Methode kann auch verwendet werden, um das Inhaltsdokument eines Iframes abzurufen, wenn sich der Iframe in derselben Domäne wie die Hauptseite befindet.

$(document).ready(function(){
    $('#frameID').load(function(){
        $('#frameID').contents().find('body').html('Hey, i`ve changed content of <body>! Yay!!!');
    });
});
Davryusha
quelle
2
Ich muss den i-Frame-Inhalt erhalten, um den Körper nicht festzulegen. Wenn ich das oben genannte mache, funktioniert es nicht. Immer leeren Körper zurückgeben
George Hanna
3
@ DarkoZ Ähm, eigentlich kam diese Antwort zuerst, also wenn überhaupt, war die andere Antwort die Kopie
michaelpri
@DarkoZ: Das Verlassen des ursprünglichen Kommentars hat mich nicht beschämt, aber ich habe 30 Sekunden damit verbracht, ein Nicht-Problem zu verstehen :) Daher ist es möglicherweise am besten, diese ganze Diskussion über eine plagiierende Antwort zu entfernen.
Dan Dascalescu
Kommentare entfernt, um Verwirrung zu vermeiden. Entschuldigung.
Darko Z
43

Wenn der iframe src von einer anderen Domain stammt, können Sie dies trotzdem tun. Sie müssen die externe Seite in PHP einlesen und von Ihrer Domain aus wiedergeben. So was:

iframe_page.php

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

    $domain = file_get_contents($URL);

    echo $domain;
?>

Dann so etwas:

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>

Das obige Beispiel zeigt, wie eine externe Seite über einen Iframe bearbeitet wird, ohne dass der Zugriff verweigert wird.

Basysmith
quelle
12
Da Ihr Server die Remote-Seite und nicht den Browser des Benutzers erhält, werden natürlich keine Cookies an die Remote-Seite gesendet. YMMV.
Mark Fowler
1
@Mark: Sie können problemlos Cookies, gepostete Daten, HTTP-Header und so weiter senden, wenn Sie diese mit der Curl-Erweiterung implementieren. php.net/manual/en/book.curl.php
Geon
2
@geon: aber der Browser sendet keine Cookies für die fremde Domain an Ihr PHP-Skript
ysth
6
@basysmith Sei achtsam: Es gibt einen Grund, warum das same origin policyexistiert, und der Vorschlag dieser Antwort ist nicht immun dagegen.
ANeves
1
Ist es in irgendeiner Weise illegal, dies zu tun?
Tallboy
32

Ich finde diesen Weg sauberer:

var $iframe = $("#iframeID").contents();
$iframe.find('selector');
zupa
quelle
Ich habe meinen Hintern gerettet - ich wurde verrückt, als ich "$ (" # iframe "). Content (). Find ()" verwendete, funktionierte aus irgendeinem Grund nicht ... dasselbe über zwei Zeilen. Keine Ahnung warum, aber es funktioniert.
Neminem
30

Verwenden

iframe.contentWindow.document

anstatt

iframe.contentDocument
Benutzer
quelle
Gute Antwort. Dies funktioniert für iFrames in anderen Domänen. Ich habe dies in der Konsole von Safari und Firefox versucht.
Aneil Mallavarapu
12
Ich glaube, es wird nur für andere Domänen funktionieren, wenn Sie es von der Konsole aus tun. Über ein Skript wird kein Zugriff gewährt.
Yincrash
Dies sollte die akzeptierte Antwort sein. Hat mein Leben gerettet und funktioniert, wenn der Iframe aus einer anderen Domäne stammt. obwohl wie erwähnt nur in der konsole.
Seidenfeuer
Für mich funktioniert iframe.contentWindow.document nicht immer. und wenn nicht, fand ich, dass $ (elem) .contents (). get (0) tut
elewinso
Sie können das "Stammdokument" in der Browserkonsole auswählen. Wenn Sie "oben" auswählen, funktioniert dies nicht als Cross-Origin-Zugriff. Wenn Sie im Namen des iframe-Dokuments darauf zugreifen, erhalten Sie natürlich Zugriff. Nur weil Sie kein Browser sind, sondern der Browser-Besitzer.
Sergei Kovalenko
26

Sie müssen ein Ereignis an den Onload-Handler eines Iframes anhängen und dort das js ausführen, damit Sie sicherstellen können, dass der Iframe vollständig geladen wurde, bevor Sie darauf zugreifen.

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

Das oben genannte Problem löst das Problem "noch nicht geladen". Wenn Sie jedoch eine Seite in den Iframe laden, die aus einer anderen Domäne stammt, können Sie aufgrund von Sicherheitsbeschränkungen nicht darauf zugreifen.

Andreas Grech
quelle
Das ist eine gute Idee, tatsächlich habe ich es versucht, als Sie geantwortet haben. Es funktioniert jedoch nicht um die verweigerte Berechtigung (es behebt, dass ich warten muss, bevor ich auf das Iframe-Zeug zugreifen kann)
rz.
eigentlich ... egal, es scheint, dass das Warten auch dann noch erforderlich ist.
rz.
Die Bereitschaftsfunktion funktioniert. Es scheint jedoch, dass es nicht darauf wartet, dass der Inhalt des Iframes vollständig geladen wird - nur für das übergeordnete Dokument, selbst wenn es für den Inhalt des Iframes selbst aufgerufen wird. Ich stelle mir vor, es liegt auch an der gleichen Herkunftspolitik.
rz.
3
Ein paar Hinweise zu diesem Code: Sie sollten iframe.contentDocument anstelle von .document verwenden und .load () anstelle von .ready () verwenden, um das Warten zu vermeiden. (Nicht perfekt, aber besser)
Rodrigo Queiro
21

Mit window.postMessage können Sie eine Funktion zwischen page und seinem iframe aufrufen (domänenübergreifend oder nicht).

Dokumentation

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

Ich bevorzuge die Verwendung einer anderen Variante für den Zugriff. Vom Elternteil aus können Sie auf eine Variable im untergeordneten Iframe zugreifen. $ist auch eine Variable und Sie können Zugriff auf ihren gerechten Aufruf erhalten window.iframe_id.$

Beispiel: window.view.$('div').hide()- Alle Divs im Iframe mit der ID 'view' ausblenden.

Aber es funktioniert nicht in FF. Für eine bessere Kompatibilität sollten Sie verwenden

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

Evgeny Karpov
quelle
2

Haben Sie den Klassiker ausprobiert und darauf gewartet, dass der Ladevorgang mit der integrierten Bereitschaftsfunktion von jQuery abgeschlossen ist?

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

K.

Khb
quelle
2
Ja. Die Bereitschaftsfunktion wird ausgeführt, wenn der Hauptrahmen geladen wird - nicht, wenn der Iframe geladen ist. Das Warten scheint jedoch ein kleiner Teil des Problems zu sein. Ich denke, das hat mit domänenübergreifender Sicherheit zu tun.
rz.
2

Ich erstelle einen Beispielcode. Jetzt können Sie leicht von verschiedenen Domains aus verstehen, dass Sie nicht auf Inhalte von iframe zugreifen können. Dieselbe Domain, auf die wir zugreifen können

Ich teile Ihnen meinen Code. Bitte führen Sie diesen Code aus. Überprüfen Sie die Konsole. Ich drucke Bild src an der Konsole. Es gibt vier Iframes, zwei Iframes, die von derselben Domain stammen, und zwei weitere von anderen Domains (Drittanbieter). Sie können zwei Bild-src sehen ( https://www.google.com/logos/doodles/2015/googles-new-logo) -5078286822539264.3-hp2x.gif

und

https://www.google.com/logos/doodles/2015/arbor-day-2015-brazil-5154560611975168-hp2x.gif ) an der Konsole und kann auch zwei Berechtigungsfehler (2 Fehler: Berechtigung für den Zugriff auf das Eigenschaftendokument verweigert) anzeigen '

... irstChild)}, Inhalt: Funktion (a) {return m.nodeName (a, "iframe")? a.contentDocument ...

), der von einem Drittanbieter stammt.

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

Ich bin hier gelandet, um den Inhalt eines Iframes ohne Abfrage zu erhalten. Für alle anderen, die danach suchen, ist es genau das:

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

Diese Lösung funktioniert genauso wie iFrame. Ich habe ein PHP-Skript erstellt, mit dem alle Inhalte von der anderen Website abgerufen werden können. Der wichtigste Teil ist, dass Sie Ihre benutzerdefinierte jQuery problemlos auf diese externen Inhalte anwenden können. Weitere Informationen finden Sie im folgenden Skript, mit dem Sie alle Inhalte von der anderen Website abrufen können. Anschließend können Sie auch Ihr cusom jQuery / JS anwenden. Dieser Inhalt kann überall, in jedem Element oder auf jeder Seite verwendet werden.

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

Für noch mehr Robustheit:

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

und

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

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