none
WebBrowserを使ったJSPページのOuterHtml取得について RRS feed

  • 質問

  • WebBrowser上でオブジェクトのOuterHtmlを取得しています。

    WebBrowserでNavigateをしてNavigate処理が終わった時点に
    取得したHtmlElementのOuterHtmlと

    その後、WebBrowser上のオブジェクトをクリックして
    取得したHtmlElementのOuterHtmlを比べましたが、

    同じオブジェクトなのにOuterHtmlの値が違います。

    以下は簡単なサンプルコードです。

    using System;
    using System.Windows.Forms;
    
    namespace OuterHtmlTest
    {
        public partial class Form1 : Form
        {
            private string urlToNavi = "http://www.ae.com";
    
            public Form1()
            {
                InitializeComponent();
    
                webBrowser1.Size = new System.Drawing.Size(455, 105);
                this.Load += new EventHandler(Form1_Load);
            }
    
            void Form1_Load(object sender, EventArgs e)
            {
                // 起動時に該当サイトへのナビ
                  webBrowser1.Navigate(urlToNavi);
            }
    
            private void webBrowser1_DocumentCompleted(object sender, 
    WebBrowserDocumentCompletedEventArgs e) { if (e.Url == webBrowser1.Url) { // ナビ許容禁止 webBrowser1.AllowNavigation = false; // WebBrowser上のクリックイベント登録 webBrowser1.Document.Click += new HtmlElementEventHandler(Document_Click); // ナビが終わった直後のHtmlElement取得 HtmlElement elem = webBrowser1.Document.All[75] as HtmlElement; MessageBox.Show("ナビが終わった直後のOuterHtml(American Eagle Outfitters)" +
    Environment.NewLine + elem.OuterHtml); } } void Document_Click(object sender, HtmlElementEventArgs e) { // WebBrowser上でクリックされたところのHtmlElement取得 HtmlElement elem = webBrowser1.Document.GetElementFromPoint(e.ClientMousePosition); MessageBox.Show("画面上のオブジェクトをクリックしたときのOuterHtml" +
    Environment.NewLine + elem.OuterHtml); } } }

    サンプルコードを動かすとWebBrowserの真ん中に
    American Eagle Outfittersというタイトルが表示されて、
    そのオブジェクトについてのOuterHtmlがMessageBoxとして表示されます。

    このときのOuterHtml値は以下のようです。

      <A href="http://www.ae.com/web/index.jsp">American Eagle Outfitters</A>

    それから、WebBrowser上でAmerican Eagle Outfittersタイトルをクリックして
    OuterHtmlを出力してみると、以下のような値が取得されます。

      <A href="http://www.ae.com/web/index.jsp" s_oid="http://www.ae.com/web/index.jsp" s_oidt="0">American Eagle Outfitters</A>

    違いとしてはナビの終わった時点のOuterHtmlには
    s_oid, s_oidtという(自作の?)Attributeが入ってないことです。

    希望としてはナビの終わった時点で、
    自作Attributeの入っているOuterHtmlを取得したいと思いますが、
    WebBrowser.Document.Allから取得するのが間違っているのでしょうか?

    ちなみに、JSP以外のサイトページでは
    両方同じOuterHtmlの値が取得できましたので、
    今の段階ではJSPページが原因だと思います。

    何卒、ご教授よろしくお願いします。

    2009年10月14日 10:15

回答

  • それは、「GetElementromPoint で取得したから」ではなく、「クリックしたから」だと思いますよ。
    onclick あたりをトリガにして JavaScript でプロパティを設定してるんでしょう。

    取得方法がどうあれ、同じ要素を指す HtmlElement は同じものです。
    • 回答としてマーク tristan28 2009年10月15日 16:20
    2009年10月15日 3:19
  • 追加です。

    webBrowser1.Document.All[75] で HtmlElement を取得した後でも、それをプログラムでクリックしてか
    ら OuterHtml を取得すれば s_oid, s_oidt が追加されます。

    具体的には以下のようにします。

    HtmlElement elem = webBrowser1.Document.All[75] as HtmlElement;
    elem.InvokeMember("click");                        // この行を追加する
    MessageBox.Show("ナビが終わった直後のOuterHtml(American Eagle Outfitters)" +
        Environment.NewLine + elem.OuterHtml);

    • 回答としてマーク tristan28 2009年10月15日 15:51
    2009年10月15日 12:59

すべての返信

  • jsp かどうかは関係なく、JavaScript によるものでしょう。
    IE7 相当の WebBrowser で試した限りは、例えば body.onload でも DocumentCompleted より後に発生しているようです。
    DocumentCompleted イベントにて Application.Idle イベントで取得するように仕掛ければ、ページロード時の処理が一通り終わったタイミングを取れるんじゃないでしょうか。
    2009年10月14日 11:06
  • Hongliangさん。

    ご回答、ありがとうございます。

    教えて頂いた方法を参考にして、
    以下のように処理を追加してみました。

    private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        if (e.Url == webBrowser1.Url)
        {
            // ナビ許容禁止
             webBrowser1.AllowNavigation = false;
    
            // WebBrowser上のクリックイベント登録
             webBrowser1.Document.Click += new HtmlElementEventHandler(Document_Click);
    
            Application.Idle += new EventHandler(Application_Idle);
        }
    }
    
    void Application_Idle(object sender, EventArgs e)
    {
        // ナビが終わった直後のHtmlElement取得
         HtmlElement elem = webBrowser1.Document.All[75] as HtmlElement;
        MessageBox.Show("ナビが終わった直後のOuterHtml(American Eagle Outfitters)" + 
                         Environment.NewLine + elem.OuterHtml);
    }
    一応、テストしてみましたが、
    自作のAttributeは取れませんでした。

    取得するタイミングをもうちょっと遅らせる必要があるのでしょうか?
    2009年10月14日 12:10
  • まあこれ以上はページ(記述された JavaScript)次第です。Ajax など使って非同期で通信している可能性もあります。
    タイマを使って取れなければいくらか待って再試行、というのも一つの手段でしょう。
    2009年10月14日 12:57
  • Hongliangさん。

    ご回答、ありがとうございます。

    >タイマを使って取れなければいくらか待って再試行
    教えて頂いた方法を参考にして試してみました。

    タイマを使って5秒置きで何分間Document.Allで取得してみましたが、
    結局、問題のAttribute(s_oid, s_oidt)は取れませんでした。

    そこで一つ質問させて頂きたいと思いますが、
    Document.All以外に別のメソッド、プロパティなどを使って
    HtmlElementを取得する方法はないのでしょうか?

    WebBrowser上をクリックしてHtmlElement取得する場合、
    Document.GetElementFromPoint()を使えば例のAttributeまで全部取れるので、
    それに相応しているメソッド/プロパティがあるのではないかと思います。

    一応、Documentのメンバーを調べてみましたが、
    いけそうなメンバーは見つけませんでした。 (_ _);

    度々質問ばかりで恐縮ですが、
    ご教授よろしくお願い致します。
    2009年10月15日 2:08
  • それは、「GetElementromPoint で取得したから」ではなく、「クリックしたから」だと思いますよ。
    onclick あたりをトリガにして JavaScript でプロパティを設定してるんでしょう。

    取得方法がどうあれ、同じ要素を指す HtmlElement は同じものです。
    • 回答としてマーク tristan28 2009年10月15日 16:20
    2009年10月15日 3:19
  • s_oid, s_oidt が現れたり消えたりするのは、OMNITURE 社の Web アクセス解析ツール
    SiteCatalyst(下記 Web Site 参照)の仕業と思います。

    OMNITURE SiteCatalyst
    http://www.sitecatalyst.jp/

    上記サイトによると、「サイトカタリストは、WEBサイトに埋め込まれたスクリプト(JavaScript)
    がアクセス情報を認識することで解析を実行するタグ型のWEBサイト分析ソリューションで
    す。」とのことです。

    問題のページにも、以下のように SiteCatalyst 関係のスクリプトが埋め込まれており、
    s_code.js の中に s_oid, s_oidt が存在します。

    <!-- START OF Omniture Code -->
    <!-- SiteCatalyst code version: H.20.3.
    Copyright 1997-2009 Omniture, Inc. More info available at
    http://www.omniture.com -->
    <script type="text/javascript"
    src="/web/javascript/omniture/s_code.js"></script>
    ・・・以下、省略・・・

    という訳で、Hongliang さんが回答されているとおり、「クリックしたから」が正解だと思います。
    (「クリック」=「アクセス」ということで、アクセス情報取得のため s_oid, s_oidt が JavaScript
    によって追加されるのだと思います)

    要するに、

    (1) もともとの HtmlElement には s_oid、s_oidt は含まれていない。

    (2) クリックした時 JavaScript がアクセス情報として s_oid、s_oidt を追加する。

    (3) Document.All とか Document.GetElementById はアクセスとは判断されず、
      s_oid、s_oidt は追加されない。

    ということだと思います。

    s_code.js を解析すれば、何故クリックしたら s_oid, s_oidt が現れるのか明確になるかもしれま
    せん。(実際、とてもそこまでやってられないと思いますが)

    2009年10月15日 12:34
  • 追加です。

    webBrowser1.Document.All[75] で HtmlElement を取得した後でも、それをプログラムでクリックしてか
    ら OuterHtml を取得すれば s_oid, s_oidt が追加されます。

    具体的には以下のようにします。

    HtmlElement elem = webBrowser1.Document.All[75] as HtmlElement;
    elem.InvokeMember("click");                        // この行を追加する
    MessageBox.Show("ナビが終わった直後のOuterHtml(American Eagle Outfitters)" +
        Environment.NewLine + elem.OuterHtml);

    • 回答としてマーク tristan28 2009年10月15日 15:51
    2009年10月15日 12:59
  • SuferOnWwwさん。

    毎度、ご回答ありがとうございます。
    素晴らしい情報収集能力と親切な説明に感動しちゃいました。(笑)

    お蔭様で問題になってた原因と
    勘違いしてたところがはっきり分かりました。

    教えて頂いたとおりに
    取得したHtmlElementに対して"click"Invoke処理をかけたら
    今まで隠れてた?s_oid, s_oidt Attributeが取れました!!

    この問題に時間を割愛してくださった皆様、
    誠にありがとうございました!! <(_ _)>


    あ、ちなみにSuferOnWwwさん。

    この件とは関係ない話ですが、
    一応、情報共有のために書きます。

    複数のFrameで構成されたサイトページのNavigate処理について
    DocumentCompletedが最終的に呼び出されるタイミングを捕捉するためには
    以下のような3つの判定方法があるようです。

    宜しければご参考にしてください。f(^^;)

    private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        // ナビ処理完了を判定
        if (webBrowser1.ReadyState == WebBrowserReadyState.Complete)
        if (!webBrowser1.IsBusy)
        if (e.Url.AbsoluteUri == webBrowser1.Url.AbsoluteUri)
        {
           // 処理内容
        }
    }

     

    • 回答としてマーク tristan28 2009年10月15日 14:24
    • 回答としてマークされていない tristan28 2009年10月15日 15:50
    • 編集済み tristan28 2009年10月15日 16:15
    2009年10月15日 14:24
  • 隠れていたんではなく、新たに設定されたんですよ。

    それはともかく、このフォーラムにおいて、「回答としてマーク」は、自分自身のレスポンスにではなく、問題解決のために役だったレスポンスに対してつけるようにしてください。
    今回のスレッドなら、SurferOnWww さんの「Click してから~」というレスに付けるのが妥当でしょう。
    2009年10月15日 14:52
  • Hongliangさん。

    ご回答、ご指摘ありがとうございます。

    指摘して頂いたことは訂正しました。

    今回の問題解決においての決定的なヒントは
    Hongliangさんからのご回答の中に書いてありましたが、
    私の勉強不足で気づいてなかったのです。 (_ _);

    ご指導、ご指摘、
    誠にありがとうございました。

    では、よろしくお願いいたします。
    2009年10月15日 16:13