計劃在WPF內嵌WebBrowser元件,並透過JavaScript取得網頁元素資訊。經過一番研究,總算試出解法,簡單筆記如下: (以擷取Google新聞網站的焦點新聞為例)

  1. 在WPF加入WebBrowser,指定Source連向Google新聞URL,另一項重點則是要指定LoadCompleted事件,該事件會在網頁載入完成後觸發,某些動作(例如: 在網頁上執行JavaScript)必須在網頁載入後執行才不致出錯。
    排版顯示純文字
    <Window x:Class="TestWebBrowser.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded_1">
        <Grid>
            <WebBrowser x:Name="browser" 
                        VerticalAlignment="Stretch" HorizontalAlignment="Stretch" 
                        Source="http://news.google.com.tw/" 
                        LoadCompleted="bowser_LoadCompleted" />
        </Grid>
    </Window>
  2. C#部分程式有幾個重點:
    1) 宣告一個ScriptHelper類別(必須為ComVisible),提供Method供網頁透過JavaScript呼叫
    2) 在Window Loaded事件中將ScriptHelper設為WebBrowser的ObjectForScripting物件
    3) 網頁載入完成時,可透過WebBrowser.InvokeScript(function_name, arg1, arg2…)呼叫網頁內的JavaScript函數。但因為我們要執行的是自訂程式作業,故藉用windows.eval()傳入要執行的JavaqScript程式字串當參數,如此達到執行任意指令的效果。
    4) 由於先前指定了ScriptHelper做為溝通物件,在JavaScript中可透過window.external.SendMessage()觸發ScriptHelper的SendMessage方法,將結果傳回.NET端。
    完整程式碼如下:
    排版顯示純文字
    using System;
    using System.Runtime.InteropServices;
    using System.Windows;
    using System.Windows.Navigation;
     
    namespace TestWebBrowser
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
     
            private void bowser_LoadCompleted(object sender, NavigationEventArgs e)
            {
                //加入ProcMessage事件,處理傳回字串
                sh.ProcMessage = (s) =>
                {
                    MessageBox.Show(s);
                };
                //執行Script,取得熱門新聞,注意: 必須要在網頁載入完成後才可呼叫
                browser.InvokeScript("eval", @"
    var list = document.getElementsByClassName('top-stories-section')[0]
               .getElementsByTagName('h2');
    var news = [];
    for (var i = 0; i < list.length; i++) {
        news.push(list[i].getElementsByTagName('span')[0].innerHTML);
    }
    window.external.SendMessage(news.join('\n'));
    ");
            }
     
            #region 供從WebBrowser網頁呼叫C#方法的溝通物件
            [ComVisible(true)]
            public class ScriptHelper
            {
                public Action<string> ProcMessage = null;
                public void SendMessage(string msg)
                {
                    if (ProcMessage != null)
                        ProcMessage(msg);
                }
            }
            private ScriptHelper sh = new ScriptHelper();
            #endregion
     
            private void Window_Loaded_1(object sender, RoutedEventArgs e)
            {
                //指定ObjectForScripting,網頁可透過window.external存取該物件
                browser.ObjectForScripting = sh;
            }
        }
    }

執行程式,就能成功用WPF抓出網頁內容囉~


Comments

# by debbie@asrc.tw

Good!

# by DEREK

請問,有出現錯誤訊息,是因為來源格式改變所影起的嗎??

# by Jeffrey

to DEREK,有錯誤訊息可以參考嗎?

Post a comment