JQuery / JavaScript: доступ к содержимому iframe

792

Я хотел бы манипулировать HTML внутри iframe, используя jQuery.

Я думал, что смогу сделать это, установив контекст функции jQuery как документ iframe, что-то вроде:

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

Однако это не похоже на работу. Немного осмотра показывает, что переменные в frames['nameOfMyIframe'], undefinedесли я не буду ждать некоторое время для загрузки iframe. Однако, когда iframe загружает переменные не доступны (я получаю permission deniedошибки -типа).

Кто-нибудь знает обойти это?

RZ.
источник
3
Что содержит iFrame - установлен ли src для другого домена?
Джеймс
если это другой домен, есть ли еще способ получить доступ к его контенту или зарегистрировать событие
adardesign,
34
Нет, потому что это будет межсайтовый скриптинг, который запрещен по соображениям безопасности. Мое решение заключалось в том, чтобы использовать прокси-сервер: передать HTML-код в IFRAME через мой собственный сайт, чтобы он больше не был межсайтовым с точки зрения браузера.
reinierpost
Это больше кросс-браузер для использования, .contentWindow.documentчем .documentна iframeэлементе. Я предлагаю изменения выше.
Алан Х.
1
Одним из способов является расширение Chrome
Мухаммед Умер

Ответы:

384

Я думаю, что то, что вы делаете, подчиняется той же политике происхождения . Это должно быть причиной, по которой вы получаете ошибки типа «отказано в разрешении» .

Онур Бебин
источник
6
@Pacerier Лучше всего проксировать содержимое iframe на вашем сайте, если вы можете ...
Tracker1
10
@ Tracker1: Можете ли вы предложить какой-либо фреймворк / API / шаблон проектирования для реализации этого прокси-решения. Любые ссылки на пример или учебник и т. Д.? Я пытался найти, но не смог найти.
Умер Хаят
3
В этом случае он подразумевает использование http-сервера, который обслуживает страницу вашего домена, в качестве прокси-сервера - запросите контент со стороннего сайта и перенаправьте его в http-ответ клиенту. Как вы, вероятно, догадываетесь, это быстро влияет на скорость отклика вашего сайта, поскольку ранее параллельные запросы вместо этого выполняются последовательно с вашим сервером как потенциальное узкое место.
Резерфорд
1
@Pacerier Потенциально любой из методов в принятом ответе здесь: stackoverflow.com/questions/3076414/… или другие (например, использование собственного домена в качестве прокси) в зависимости от того, чего вы хотите достичь.
Марк Амери
4
Для справки, я просто настроил нечто похожее: если вы не хотите, чтобы результат был невероятно медленным, просто настройте свой веб-сервер так, чтобы он перенаправлял запросы ресурсов (CSS / JS / images) на исходный сайт, поэтому ваш прокси только управляет запросами HTML. Я просматриваю удаленный сайт под localhost прямо сейчас, и он абсолютно прозрачен :)
neemzy
985

Если <iframe>это из того же домена, элементы легко доступны как

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

Ссылка

Ясир Лагхари
источник
157
Знать об одной и той же политике происхождения - это здорово, но это ответ, который делает то, что хотел ОП. Почему другой ответ был выбран как правильный?
Джейсон Светт
2
Вы должны использовать прокси, чтобы получить HTML в вашем источнике. Например, johnchapman.name/…
mhenry1384
7
@JasonSwett, я предполагаю, что проблема ОП - действительно same origin policy, и в этом случае этот ответ не является решением для него.
ANeves
3
@fizzbuzz Затем вы получаете IFrame точно так же, как и любой другой контент без идентификатора с jQuery: вы выбираете соответствующий тег <IFrame> с помощью CSS, используя имена классов и значения атрибутов, чтобы сузить его при необходимости.
Auspex
2
Там нет никакого метода называется содержимым для фрейма.
Ренан
88

Вы можете использовать .contents()метод jQuery.

Этот .contents()метод также можно использовать для получения документа содержимого iframe, если iframe находится в том же домене, что и главная страница.

$(document).ready(function(){
    $('#frameID').load(function(){
        $('#frameID').contents().find('body').html('Hey, i`ve changed content of <body>! Yay!!!');
    });
});
davryusha
источник
2
мне нужно получить содержимое фрейма i, чтобы не задавать тело ..... Когда я делаю вышеописанное, оно не работает, всегда возвращайте пустое тело
Джордж Ханна
3
@DarkoZ Хм, на самом деле этот ответ пришел первым, так что, если что, другим ответом была копия
michaelpri
@DarkoZ: оставив исходный комментарий, я вас не опозорил, но я потратил впустую, как 30 секунд, пытаясь понять несущественную проблему :) Так что лучше всего удалить всю эту дискуссию о плагиатизирующем ответе.
Дан Даскалеску
комментарии удалены, чтобы избежать путаницы. Извинения.
Дарко Z
43

Если iframe src из другого домена, вы все равно можете это сделать. Вам нужно прочитать внешнюю страницу в PHP и отобразить ее с вашего домена. Нравится:

iframe_page.php

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

    $domain = file_get_contents($URL);

    echo $domain;
?>

Тогда как то так:

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>

Выше приведен пример того, как редактировать внешнюю страницу через iframe без доступа и т.д.

basysmith
источник
12
Конечно, поскольку ваш сервер получает удаленную страницу, а не браузер пользователя, файлы cookie не будут отправляться на удаленную страницу. YMMV.
Марк Фаулер
1
@Mark: вы можете легко отправлять файлы cookie, размещенные данные, HTTP-заголовки и еще много чего, если внедрите их с расширением curl. php.net/manual/en/book.curl.php
geon
2
@geon: но браузер не будет отправлять куки для внешнего домена на ваш PHP скрипт
ysth
6
@basysmith Будьте внимательны: есть причина, почему same origin policyсуществует, и предложение этого ответа не застраховано от этого.
ANeves
1
это незаконно в любом случае?
Tallboy
32

Я нахожу этот способ чище:

var $iframe = $("#iframeID").contents();
$iframe.find('selector');
Зупа
источник
Спасла мою задницу - я сходил с ума, используя "$ (" # iframe "). Contents (). Find ()" по какой-то причине не работало ... То же самое делали две строки. Не знаю почему, но это работает.
Неминем,
30

использование

iframe.contentWindow.document

вместо

iframe.contentDocument
пользователь
источник
Отличный ответ. Это работает для iFrames в других доменах. Я попробовал это в консоли на Safari и Firefox.
Анейл Маллаварапу
12
Я считаю, что это будет работать только для других доменов, если вы делаете это с консоли. Из скрипта доступ не будет разрешен.
Инкраш
Это должен быть принятый ответ. Спасла мою жизнь и работает, когда iframe из другого домена; хотя, как уже упоминалось, только в консоли.
шелковый огонь
для меня iframe.contentWindow.document не всегда работает. и когда это не так, я обнаружил, что $ (elem) .contents (). get (0) делает
elewinso
Вы можете выбрать «корневой документ» в консоли браузера. Когда вы выбираете "top", он не будет работать, как доступ к источникам. Если вы решите получить доступ от имени документа iframe, конечно, он предоставит вам доступ. Просто потому, что вы не браузер, а владелец браузера.
Сергей Коваленко
26

Вам необходимо прикрепить событие к обработчику загрузки iframe и выполнить там js, чтобы убедиться, что iframe завершил загрузку, прежде чем получить к нему доступ.

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

Вышеприведенное решение решит проблему «еще не загружен», но в том, что касается разрешений, если вы загружаете страницу в iframe из другого домена, вы не сможете получить к ней доступ из-за ограничений безопасности.

Андреас Греч
источник
это хорошая идея, на самом деле я пытался это так же, как вы ответили. Тем не менее, это не работает в отношении разрешения «отказано» (оно касается того, что мне пришлось ждать, прежде чем начать доступ к элементу iframe)
rz.
на самом деле ... неважно, кажется, что ожидание все еще требуется даже при этом.
рз.
Готовая функция работает. Однако, похоже, что он не ожидает окончания загрузки содержимого iframe - только для родительского документа, даже если он вызывается для содержимого самого iframe. Я предполагаю, что это также из-за той же политики происхождения.
рз.
3
Несколько замечаний по этому коду: вы должны использовать iframe.contentDocument вместо .document, и вы должны использовать .load () вместо .ready (), чтобы избежать ожидания. (Не идеально, но лучше)
Родриго Кейро
21

Вы можете использовать window.postMessage для вызова функции между страницей и его iframe (кросс-домен или нет).

Документация

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
источник
4

Я предпочитаю использовать другой вариант для доступа. Из parent вы можете получить доступ к переменной в дочернем iframe. $переменная тоже, и вы можете получить доступ к ее просто вызову window.iframe_id.$

Например, window.view.$('div').hide()- скрыть все div в iframe с идентификатором 'view'

Но это не работает в FF. Для лучшей совместимости вы должны использовать

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

Евгений Карпов
источник
2

Вы пробовали классический вариант, ожидая завершения загрузки, используя встроенную функцию готовности jQuery?

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

К

ХО
источник
2
Да. Функция ready начинает выполняться при загрузке основного кадра, а не при загрузке iframe. Ожидание, кажется, небольшая часть проблемы, все же. Я думаю, что это связано с междоменной безопасностью.
рз.
2

Я создаю пример кода. Теперь вы можете легко понять из другого домена, что вы не можете получить доступ к содержимому iframe .. Тот же домен, к которому мы можем получить доступ к содержимому iframe

Я поделился с вами своим кодом, пожалуйста, запустите этот код, проверьте консоль. Я печатаю изображение src на консоли. Существует четыре iframe, два iframe, поступающие из одного домена, и два других из другого домена (третье лицо). Вы можете увидеть два изображения src ( https://www.google.com/logos/doodles/2015/googles-new-logo -5078286822539264,3-hp2x.gif

а также

https://www.google.com/logos/doodles/2015/arbor-day-2015-brazil-5154560611975168-hp2x.gif ) в консоли, а также может отображаться две ошибки разрешения (2 Ошибка: в доступе к свойству «доступ запрещен» '

... irstChild)}, содержимое: function (a) {return m.nodeName (a, "iframe")? a.contentDocument ...

) который идет от стороннего iframe.

<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
источник
1

Я остановился здесь на поиске содержимого iframe без jquery, так что для всех, кто ищет это, именно так:

document.querySelector('iframe[name=iframename]').contentDocument
Джефф Дэвис
источник
1

Это решение работает так же, как iFrame. Я создал PHP-скрипт, который может получить все содержимое с другого сайта, и наиболее важной частью является то, что вы можете легко применить свой пользовательский jQuery к этому внешнему контенту. Пожалуйста, обратитесь к следующему сценарию, который может получить все содержимое с другого веб-сайта, а затем вы также можете применить свой cusom jQuery / JS. Этот контент может использоваться где угодно, внутри любого элемента или любой страницы.

<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

Для еще большей надежности:

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

а также

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

if (frame_win) {
  $(frame_win.contentDocument || frame_win.document).find('some selector').doStuff();
  ...
}
...
Доминик Фортин
источник