jQuery / JavaScript:iframeのコンテンツへのアクセス


792

jQueryを使用してiframe内のHTMLを操作したいと思います。

次のように、jQuery関数のコンテキストをiframeのドキュメントに設定することで、これを実行できると思いました。

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

しかし、これはうまくいかないようです。少し調べてみると、iframeが読み込まれるまでしばらく待たなければ、の変数がframes['nameOfMyIframe']残っundefinedていることがわかります。ただし、iframeの読み込み時に変数にアクセスできません(permission denied-typeエラーが発生します)。

誰かがこれの回避策を知っていますか?


3
iFrameには何が含まれていますか?そのsrcは別のドメインに設定されていますか?
ジェームズ

それが他のドメインである場合、そのコンテンツにアクセスしたり、イベントを登録したりする方法はまだありますか
adardesign

34
いいえ、それはクロスサイトスクリプティングになるため、セキュリティ上の理由から禁止されています。私の解決策はプロキシを使用することでした:IFRAMEのHTMLをそのまま自分のサイトにフィードして、ブラウザーの観点からクロスサイトではなくなりました。
reinierpost 2010

要素.contentWindow.documentよりもクロスブラウザを使用.documentiframeます。上記の変更を提案します。
アラン

1
1つの方法は、Chrome拡張機能です
Muhammad Umer 2013

回答:


384

私はあなたがしていることは同じ起源の方針の対象であると思います。これが、アクセス拒否の型エラーが発生する理由です。


6
@Pacerier最善の策は、可能であれば、サイトのiframeのコンテンツをプロキシすることです...
Tracker1

10
@ Tracker1:このプロキシソリューションを実装するためのフレームワーク/ api /デザインパターンを提案できますか。例やチュートリアルなどへのリンクはありますか?検索を試みましたが、見つかりませんでした。
Umer Hayat

3
この場合、彼はドメインのページをプロキシとして使用しているhttpサーバーを使用することを意味します-サードパーティのサイトからコンテンツをリクエストし、http応答でクライアントに転送します。おそらく推測できるように、以前の並列リクエストが代わりに潜在的なボトルネックとしてサーバーと直列に実行されるため、サイトの応答性にすぐに影響します。
ラザフォード、2013年

1
@Pacerier潜在的にここで受け入れられた回答のいずれかのメソッド:stackoverflow.com/questions/3076414/…または他のもの(自分のドメインをプロキシとして使用するなど)。
Mark Amery 2013

4
記録のために、私は同じようなものを設定しました:結果が信じられないほど遅くなることを望まない場合は、アセットリクエスト(CSS / JS / images)を元のWebサイトに直接転送するようにWebサーバーを設定するだけで、プロキシHTMLリクエストのみを管理します。私は現在localhostの下で遠くのサイトを閲覧していますが、それは完全に透過的です:)
neemzy

985

<iframe>が同じドメインからのものである場合、要素には次のように簡単にアクセスできます。

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

参照


157
同じオリジンのポリシーについて知ることは素晴らしいことですが、これはOPが望んでいたことを実行する答えです。なぜ他の答えが正しいものとして選ばれたのですか?
Jason Swett、2010年

2
オリジンでHTMLを取得するには、プロキシを使用する必要があります。たとえば、johnchapman.name /…
mhenry1384

7
@JasonSwett、私の推測では、OPの問題は確かにsame origin policyであり、その場合、この答えは彼の解決策ではありません。
ANeves

3
@fizzbuzz次に、jQueryで他のIDのないコンテンツを取得するのと同じ方法でIFrameを取得します。CSSで適切な<IFrame>タグを選択し、必要に応じてクラス名と属性値を使用して絞り込みます。
Auspex 2012

2
iframeのコンテンツと呼ばれるメソッドはありません。
レナン、2013

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

2
ボディを設定しないようにiフレームのコンテンツを取得する必要があります.....上記を実行しても機能しません。常に空のボディが返されます
George Hanna

3
@DarkoZええと、実際にはこの答えが最初に来たので、どちらかと言えば、他の答えはコピーでした
マイケルプリ2015年

@DarkoZ:元のコメントを残しても恥ずかしくはありませんでしたが、問題ではないことを理解しようとして30秒ほど無駄にしたのでした。
Dan Dascalescu、2015年

混乱を避けるためにコメントを削除しました。謝罪。
Darko 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を介して外部ページを編集する方法の例です...


12
もちろん、サーバーはユーザーのブラウザーではなくリモートページを取得しているため、Cookieはリモートページに送信されません。YMMV。
Mark Fowler、

1
@Mark:Cookie、投稿されたデータ、HTTPヘッダーなどをcurl拡張機能で実装すると、簡単に送信できます。php.net/manual/en/book.curl.php
geon

2
@geon:しかし、ブラウザは外部ドメインのCookieをPHPスクリプトに送信しません
ysth

6
@basysmith注意してください:がsame origin policy存在する理由があり、この回答の提案はそれに影響されません。
ANeves

1
これを行うことは何らかの方法で違法ですか?
トールボーイ、2012

32

私はこのようにすっきりとしています:

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

お尻を救った-私は "$("#iframe ")。contents()。find()"を使用して頭がおかしくなりました...なんらかの理由で機能しませんでした... 2行で同じことを行いました。なぜだろう、しかしそれはうまくいく。
neminem

30

使用する

iframe.contentWindow.document

の代わりに

iframe.contentDocument

すばらしい答えです。これは、他のドメインのiFrameで機能します。SafariとFirefoxのコンソールでこれを試しました。
Aneil Mallavarapu 2010

12
コンソールから実行している場合は、他のドメインでしか機能しないと思います。スクリプトからのアクセスは許可されません。
yincrash '31年

これは受け入れられる答えになるはずです。私の命を救い、iframeが別のドメインのものである場合に機能します。前述のとおり、コンソールのみ。
シルクファイア2014

私にとってiframe.contentWindow.documentは常に機能するとは限りません。そして、それが見つからない場合、$(elem).contents()。get(0)がそうであることがわかりました
elewinso

ブラウザコンソールで「ルートドキュメント」を選択できます。「トップ」を選択すると、クロスオリジンアクセスとして機能しなくなります。もちろん、iframeドキュメントの代わりにアクセスすることを選択した場合は、アクセスが許可されます。あなたがブラウザではなく、ブラウザの所有者だからです。
Sergei Kovalenko

26

イベントをiframeのonloadハンドラーにアタッチし、そこで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。

実際に...気にしないでください。これを行う場合でも待機が必要なようです。
rz。

レディ機能が働きます。ただし、iframeのコンテンツの読み込みが完了するのを待機していないようです。iframe自体のコンテンツで呼び出された場合でも、親ドキュメントに対してのみです。同じ起源政策のせいだと思います。
rz。

3
このコードに関する注意点:待機を回避するには、.documentではなくiframe.contentDocumentを使用し、.ready()ではなく.load()を使用する必要があります。(完璧ではないが、より良い)
ロドリゴケイロ2009

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>

4

アクセスには他のバリアントを使用することを好みます。親から子iframeの変数にアクセスできます。 $も変数であり、その公正な呼び出しへのアクセスを受け取ることができます window.iframe_id.$

たとえばwindow.view.$('div').hide()、iframe内のすべてのdivを非表示にします。

ただし、FFでは機能しません。より良い互換性のためにあなたは使うべきです

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


2

jQueryの組み込みの準備完了関数を使用してロードが完了するのを待って、クラシックを試しましたか?

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

K


2
はい。レディ関数は、iframeが読み込まれたときではなく、メインフレームが読み込まれたときに実行を開始します。ただし、待機は問題の小さな部分のようです。それはクロスドメインセキュリティに関係していると思います。
rz。

2

サンプルコードを作成します。これで、iframeのコンテンツにアクセスできない別のドメインから簡単に理解できます。iframeコンテンツにアクセスできるのと同じドメイン

コードを共有します。このコードを実行して、コンソールを確認してください。コンソールで画像srcを印刷します。4つのiframeがあり、2つのiframeが同じドメインからのもので、他の2つが他のドメイン(サードパーティ)からのものです。2つの画像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つのアクセス許可エラー(2エラー:プロパティ 'ドキュメントへのアクセスが拒否されました」

... irstChild)}、contents: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>

1

私はここでjqueryなしでiframeのコンテンツを取得することを探していたので、それを探している他の人にとっては、これは次のとおりです。

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

1

このソリューションはiFrameと同じように機能します。私は他のWebサイトからすべてのコンテンツを取得できる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();
  ...
}
...
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.