2013年12月14日 星期六

C# WebBrowser抓取HTML原始碼與AJAX動態產生的內容‏

C# 的 WebBrowser 通用控制項,可以用來瀏覽網頁。

若要經由 WebBrowser 取得網頁原始碼內容,可在 WebBrowser 的 DocumentCompleted 事件內,利用 WebBrowser.DocumentStream 屬性讀取 Stream 內容,或是用 WebBrowser.DocumentText 屬性取得原始碼字串文字。

但要取得 AJAX 產生的動態內容時,必須監聽 DOM 元素的 onpropertychange 事件,當 onpropertychange 事件觸發時,才去讀取目前頁面的內容。
(onpropertychange 事件在頁面元素的內容改變時,就會觸發)


範例:
test.html (HTML 頁面,每兩秒執行一次 AJAX,取得伺服器時間,更新在<div id="abc"></div>元素內 )
<!DOCTYPE HTML>
<html lang="en-US">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        <script>
            $.ajaxSetup({
                cache: false
            });
            var aa = function() {
                $.get("ajax.php", function(data) {
                    $("#abc").html(data);
                });
            };

            $(function() {
                aa();
                setInterval(aa, 2000);
            });
        </script>
    </head>
    <body>
        <div id="abc"></div>
    </body>
</html>
ajax.php (PHP頁面,輸出目前時間)
<?php
echo date("H:i:s");
C# 程式
private void button1_Click(object sender, EventArgs e)
{
    webBrowser1.Navigate("http://127.0.0.1/test.html");
}

private void handlerAbc(Object sender, EventArgs e)
{
    HtmlElement elm = webBrowser1.Document.GetElementById("abc");
    if (elm == null) return;
    Console.WriteLine("elm.InnerHtml(handlerAbc):" + elm.InnerHtml);
}

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    /* 抓取網頁原始碼 方法1*/
    System.IO.StreamReader getReader = new System.IO.StreamReader(webBrowser1.DocumentStream, System.Text.Encoding.Default);
    string htmlA = getReader.ReadToEnd(); // htmlA 只能抓到網頁原始碼

    /* 抓取網頁原始碼 方法1*/
    string htmlB = webBrowser1.DocumentText; // htmlB 只能抓到網頁原始碼

    /* 取得 AJAX 動態改變的內容,可用以下方法 */
    HtmlElement elm = webBrowser1.Document.GetElementById("abc"); // 取的id為abc的元素 
    Console.WriteLine("elm.InnerHtml(DocumentCompleted):" + elm.InnerHtml);
    if (elm != null)
    {
        // 新增 handlerAbc 方法,監聽abc元素的 onpropertychange 事件,
        elm.AttachEventHandler("onpropertychange", new EventHandler(handlerAbc));
    }

}
執行結果:
elm.InnerHtml(DocumentCompleted):
elm.InnerHtml(handlerAbc):06:32:36
elm.InnerHtml(handlerAbc):06:32:38
elm.InnerHtml(handlerAbc):06:32:40


參考:
WebBrowser.DocumentStream 屬性
WebBrowser.DocumentText 屬性
HtmlElement.AttachEventHandler 方法
C# WebBrowser control — Get Document Elements After AJAX?
webBrowser1_DocumentCompleted 不停被調用
實時監聽輸入框值變化的完美方案:oninput & onpropertychange

1 則留言: