jQuery / JavaScript: accéder au contenu d'un iframe

792

Je voudrais manipuler le HTML à l'intérieur d'un iframe en utilisant jQuery.

Je pensais pouvoir le faire en définissant le contexte de la fonction jQuery comme étant le document de l'iframe, quelque chose comme:

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

Cependant, cela ne semble pas fonctionner. Un peu d'inspection me montre que les variables frames['nameOfMyIframe']sont à undefinedmoins que j'attende un moment que l'iframe se charge. Cependant, lorsque l'iframe se charge, les variables ne sont pas accessibles (j'obtiens des permission deniederreurs de type).

Quelqu'un connaît-il une solution à ce problème?

rz.
la source
3
Que contient l'iFrame - son src est-il réglé sur un autre domaine?
James
s'il s'agit d'un autre domaine, existe-t-il encore un moyen d'accéder à son contenu ou d'enregistrer un événement
adardesign
34
Non, car ce serait du scriptage intersite, ce qui est interdit pour des raisons de sécurité. Ma solution consistait à utiliser un proxy: alimenter le HTML dans l'IFRAME textuellement à travers mon propre site afin qu'il ne soit plus intersite du point de vue du navigateur.
reinierpost
C'est plus multi-navigateur à utiliser .contentWindow.documentque .documentsur l' iframeélément. Je proposerai le changement ci-dessus.
Alan H.
1
une façon est les extensions chromées
Muhammad Umer

Réponses:

384

Je pense que ce que vous faites est soumis à la même politique d'origine . Cela devrait être la raison pour laquelle vous obtenez des erreurs de type d'autorisation refusée .

Onur Bebin
la source
6
@Pacerier Le meilleur pari est de proxy le contenu de l'iframe sur votre site, si vous le pouvez ...
Tracker1
10
@ Tracker1: Pouvez-vous suggérer n'importe quel modèle de framework / api / design pour implémenter cette solution proxy. Des liens vers un exemple ou un tutoriel, etc.? J'ai essayé de chercher mais je n'en ai pas trouvé.
Umer Hayat
3
Dans ce cas, il signifie utiliser le serveur http qui sert la page de votre domaine comme proxy - demander le contenu du site tiers et le transmettre dans la réponse http au client. Comme vous pouvez probablement le deviner, cela a un impact rapide sur la réactivité de votre site car les requêtes précédemment parallèles sont plutôt exécutées en série avec votre serveur comme goulot d'étranglement potentiel.
rutherford
1
@Pacerier Potentiellement l'une des méthodes de la réponse acceptée ici: stackoverflow.com/questions/3076414/… ou autres (comme utiliser votre propre domaine comme proxy), en fonction de ce que vous voulez réaliser.
Mark Amery
4
Pour mémoire, je viens de configurer quelque chose de similaire: si vous ne voulez pas que le résultat soit incroyablement lent, configurez simplement votre serveur Web pour rediriger directement les demandes d'actifs (CSS / JS / images) vers le site Web d'origine, donc votre proxy gère uniquement les requêtes HTML. Je suis en train de parcourir un site distant sous localhost en ce moment et c'est absolument transparent :)
neemzy
985

Si le <iframe>est du même domaine, les éléments sont facilement accessibles comme

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

Référence

Yasir Laghari
la source
157
Connaître la même politique d'origine est génial, mais c'est la réponse qui fait ce que le PO voulait. Pourquoi l'autre réponse a-t-elle été choisie comme la bonne?
Jason Swett
2
Vous devez utiliser un proxy pour obtenir le code HTML de votre origine. Par exemple, johnchapman.name/…
mhenry1384
7
@JasonSwett, je suppose que le problème d'OP est bien le same origin policy, auquel cas cette réponse n'est pas une solution pour lui.
ANeves
3
@fizzbuzz Ensuite, vous obtenez l'IFrame de la même manière que vous obtiendrez tout autre contenu sans identifiant avec jQuery: vous sélectionnez la balise <IFrame> appropriée avec CSS, en utilisant des noms de classe et des valeurs d'attribut pour l'affiner si nécessaire.
Auspex
2
Il n'y a pas de méthode appelée contenu pour l'iframe.
Renan
88

Vous pouvez utiliser la .contents()méthode de jQuery.

La .contents()méthode peut également être utilisée pour obtenir le document de contenu d'un iframe, si l'iframe est sur le même domaine que la page principale.

$(document).ready(function(){
    $('#frameID').load(function(){
        $('#frameID').contents().find('body').html('Hey, i`ve changed content of <body>! Yay!!!');
    });
});
davryusha
la source
2
J'ai besoin d'obtenir le contenu du cadre i pour ne pas définir le corps ..... Quand je fais ce qui précède, cela ne fonctionne pas toujours retourner le corps vide
George Hanna
3
@DarkoZ Um, en fait, cette réponse est venue en premier, donc si quoi que ce soit, l'autre réponse était la copie
michaelpri
@DarkoZ: laisser le commentaire original ne m'a pas fait honte, mais j'ai perdu 30 secondes à essayer de comprendre un non-problème :) Donc, supprimer toute cette discussion sur une réponse plagiante pourrait être mieux.
Dan Dascalescu
commentaires supprimés pour éviter toute confusion. excuses.
Darko Z
43

Si le src iframe provient d'un autre domaine, vous pouvez toujours le faire. Vous devez lire la page externe en PHP et l'écho de votre domaine. Comme ça:

iframe_page.php

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

    $domain = file_get_contents($URL);

    echo $domain;
?>

Alors quelque chose comme ça:

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>

Ce qui précède est un exemple de modification d'une page externe via un iframe sans que l'accès soit refusé, etc.

forgeron
la source
12
Bien sûr, parce que votre serveur obtient la page distante et non le navigateur de l'utilisateur, aucun cookie ne sera envoyé à la page distante. YMMV.
Mark Fowler
1
@Mark: Vous pouvez facilement envoyer des cookies, des données publiées, des en-têtes HTTP et ainsi de suite si vous l'implémentez avec l'extension curl. php.net/manual/en/book.curl.php
geon
2
@geon: mais le navigateur n'enverra pas de cookies pour le domaine étranger à votre script PHP
ysth
6
@basysmith Soyez conscient: il y a une raison pour laquelle il same origin policyexiste, et la proposition de cette réponse n'y échappe pas.
ANeves
1
est-il illégal de faire cela?
Tallboy
32

Je trouve cette façon plus propre:

var $iframe = $("#iframeID").contents();
$iframe.find('selector');
zupa
la source
J'ai sauvé mes fesses - je devenais fou, en utilisant "$ (" # iframe "). Contents (). Find ()" ne fonctionnait pas pour une raison quelconque ... même chose sur deux lignes. Je ne sais pas pourquoi, mais ça marche.
neminem
30

Utilisation

iframe.contentWindow.document

au lieu de

iframe.contentDocument
utilisateur
la source
Très bonne réponse. Cela fonctionne pour les iFrames dans d'autres domaines. J'ai essayé cela dans la console sur Safari et Firefox.
Aneil Mallavarapu
12
Je crois que cela ne fonctionnera que pour d'autres domaines si vous le faites à partir de la console. À partir d'un script, l'accès ne sera pas autorisé.
yincrash
Ce devrait être la réponse acceptée. M'a sauvé la vie et fonctionne lorsque l'iframe provient d'un domaine différent; bien que comme mentionné, uniquement dans la console.
silkfire
pour moi iframe.contentWindow.document ne fonctionne pas toujours. et quand ce n'est pas le cas, j'ai trouvé que $ (elem) .contents (). get (0) le fait
elewinso
vous pouvez choisir le "document racine" dans la console du navigateur. Lorsque vous sélectionnez "top", cela ne fonctionnera pas, comme un accès d'origine croisée. Si vous choisissez d'accéder au nom du document iframe, cela vous donnera bien sûr accès. Tout simplement parce que vous n'êtes pas un navigateur, mais le propriétaire du navigateur.
Sergei Kovalenko
26

Vous devez attacher un événement au gestionnaire de chargement d'une iframe et y exécuter les js, afin de vous assurer que l'iframe a fini de se charger avant d'y accéder.

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

Ce qui précède résoudra le problème `` pas encore chargé '', mais en ce qui concerne les autorisations, si vous chargez une page dans l'iframe qui provient d'un domaine différent, vous ne pourrez pas y accéder en raison de restrictions de sécurité.

Andreas Grech
la source
c'est une bonne idée, en fait je l'essayais juste comme vous l'avez répondu. Cependant, cela ne fonctionne pas autour de l'autorisation refusée (cela résout le fait que je doive attendre avant de commencer à accéder au contenu iframe)
rz.
en fait ... peu importe, il semble que l'attente soit toujours requise même en faisant cela.
rz.
La fonction prête fonctionne. Cependant, il semble qu'il n'attende pas que le contenu de l'iframe finisse de se charger - uniquement pour le document parent même lorsqu'il est invoqué sur le contenu de l'iframe lui-même. J'imagine que c'est aussi à cause de la même politique d'origine.
rz.
3
Quelques remarques sur ce code: vous devez utiliser iframe.contentDocument au lieu de .document, et vous devez utiliser .load () au lieu de .ready () pour éviter l'attente. (Pas parfait, mais mieux)
Rodrigo Queiro
21

Vous pouvez utiliser window.postMessage pour appeler une fonction entre la page et son iframe (cross-domain ou non).

Documentation

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
la source
4

Je préfère utiliser une autre variante pour y accéder. Du parent, vous pouvez avoir accès à une variable dans l'iframe enfant. $est aussi une variable et vous pouvez avoir accès à son appel juste window.iframe_id.$

Par exemple, window.view.$('div').hide()- masquez toutes les divs dans iframe avec l'id 'view'

Mais cela ne fonctionne pas dans FF. Pour une meilleure compatibilité, vous devez utiliser

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

Evgeny Karpov
la source
2

Avez-vous essayé le classique en attendant la fin de la charge en utilisant la fonction prête à l'emploi de jQuery?

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

K

Khb
la source
2
Oui. La fonction prête commence à s'exécuter lorsque le cadre principal est chargé - pas lorsque l'iframe est chargé. L'attente semble cependant être une petite partie du problème. Je pense que cela a à voir avec la sécurité inter-domaines.
rz.
2

Je crée un exemple de code. Maintenant, vous pouvez facilement comprendre à partir d'un domaine différent que vous ne pouvez pas accéder au contenu de iframe .. Même domaine, nous pouvons accéder au contenu iframe

Je vous partage mon code, veuillez exécuter ce code, vérifiez la console. J'imprime l'image src sur la console. Il y a quatre iframe, deux iframe provenant du même domaine et deux autres d'un autre domaine (tiers) .Vous pouvez voir deux images src ( https://www.google.com/logos/doodles/2015/googles-new-logo -5078286822539264.3-hp2x.gif

et

https://www.google.com/logos/doodles/2015/arbor-day-2015-brazil-5154560611975168-hp2x.gif ) sur la console et peut également voir deux erreurs d'autorisation (2 Erreur: autorisation refusée pour accéder au document de la propriété) "

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

) qui provient d'un iframe tiers.

<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
la source
1

Je me suis retrouvé ici à chercher le contenu d'une iframe sans jquery, donc pour quiconque le recherche, c'est juste ceci:

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

Cette solution fonctionne de la même manière que iFrame. J'ai créé un script PHP qui peut obtenir tous les contenus de l'autre site Web, et le plus important est que vous pouvez facilement appliquer votre jQuery personnalisée à ce contenu externe. Veuillez vous référer au script suivant qui peut obtenir tout le contenu de l'autre site Web, puis vous pouvez également appliquer votre jQuery / JS cusom. Ce contenu peut être utilisé n'importe où, à l'intérieur de n'importe quel élément ou de n'importe quelle page.

<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
la source
0

Pour encore plus de robustesse:

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

et

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

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