[Windows Phone/C#] C# 網頁擷取資料 解析網頁標籤(HTML Parser )API -HTML Agility Pack 以Windows Phone 8 為例

  • 31065
  • 0
  • C#
  • 2013-11-27

有時候我們會需要開發一些App是需要擷取網路上的一些資料,並且那些資料可能沒有提供方便的XML或Json的格式資料,這個時候我們便需要去解析(Parsing)網頁上HTML結構來取得HTML中的資料

在Java上有方便的Jsoup或apacheAPI提供的HTML Parser等工具方便我們快速完成取得想一的資料;那麼在C#上呢? 有沒有類似這樣專門提供、協助我們做HTML Parsing的工具?

有的。 它叫做HTML Agility Pack (可以點入此連結有相關詳細範例教學^.<)

而這邊我們以Windows Phone8( 以下簡稱WP8 )為範例,如果有打算在WP8上使用,但是不知道怎麼做的人,可以看看這篇^.<

前言

 


 

有時候我們會需要開發一些App是需要擷取網路上的一些資料,並且那些資料可能沒有提供方便的XML或Json的格式資料,這個時候我們便需要去解析(Parsing)網頁上HTML標籤與結構來取得HTML中的資料

 

在Java上有方便的Jsoup或apacheAPI提供的HTML Parser等工具方便我們快速完成取得想一的資料;那麼在C#上呢? 有沒有類似這樣專門提供、協助我們做HTML Parsing的工具?

有的。 它叫做HTML Agility Pack (可以點入此連結有相關詳細範例教學^.<)

 

而這邊我們以Windows Phone8( 以下簡稱WP8 )為範例,如果有打算在WP8上使用,但是不知道怎麼做的人,可以看看這篇^.<

 

加入HTML Agility Pack到專案

 


 

可以選擇使用NuGet的方式或是手動下載API的dll檔

1﹒去HTML Agility Pack 下載HAP 1.4.6

下載下來後解壓縮,並在專案中參考sl4-windowsphone71 (開發WP7也是選擇sl4-windowsphone71,但是完成下述的介紹後,仍是行不通,試試看使用sl3-wp資料夾中的dll檔,不過程式碼的部分可能會有點不一樣)

download

wp

 

2﹒使用NuGet套件安裝

VS中工具->程式庫套件管理員->管理NuGet套件,會出現如下圖的視窗,此時在右邊的搜尋框打入Html就會出現下面的套件

HtmlAgilityPack,點選並安裝

nuget htmlagileparser

 

如果你再開發WP8的時候,透過上述的方式安裝會顯示以下畫面:

則可以透過方法一來完成加入參考

 

此時透過上述的兩種方法之一,在完成後就會在你的專案參考中看到HtmlAgilityPack dll檔案

ref

 

由於HtmlAgilityPack 是使用一種XPath的路徑語言方式來取得HTML中的階層標籤中的元素,所以在這邊我們需要引入XPath的dll檔

好家在,在.Net中的Silverlight中有提供此dll檔,於是我們可以在此參考她,在C槽路徑下的

ProgramFiles(x86)%\Microsoft SDKs\Microsoft SDKs\Silverlight\v4.0\Libraries\Client

或是

ProgramFiles%\Microsoft SDKs\Microsoft SDKs\Silverlight\v4.0\Libraries\Client

可以找到

xPathdll

 

ref xpath

 

這樣就準備完成囉!

 

這邊稍微提醒一下,如果你使用NuGet的方式安裝時,上述的做法雖然完成但是開始編寫執行後,若還是有出現問題,可以改用sl3-wp試試看(本人沒遇到這個問題,不過網路上以些人是使用sl3-wp才可以,但是程式語法可能會不太一樣唷!)

請手動移掉所參考的HtmlAgilityPack ,然後重新手動加入試試看sl3-wp的HtmlAgilityPack 的dll檔案(在專案底下會多出一個Package資料夾)

package

 

 

使用HTML Agility Pack Parsing

 


 

基本上不同的開發平台下,API中的使用會有稍微不同(例如官方範例是WPF,與在WP手機上的使用或是某些方法的命名就不一樣)

在這邊我們是以WP8為例,我要解析的網站範例的Yahoo的星座運勢(Yahoo->星座算命->星座),如下圖:

water

example

 

例如我要取得整體運中的這串文字,在他的標籤層級很多,如果要一個一個下會很麻煩,這個時候應用XPath的方式來解析的HtmlAgilityPack ,處理就很方便了。

先看我們如何取得這個網頁:

HtmlWeb client = new HtmlWeb();
client.LoadCompleted += client_LoadCompleted;
client.LoadAsync("http://astro.click108.com.tw/daily_10.php?iAstro=10");

 

上述的處理方式是先初始化HtmlAgilityPack 的HtmlWeb 類別(這邊在WP7的使用方式就有些不同,不過你也可以使用.Net提供的HttpWebRequest來取得網頁)

如果要同時處理多個網頁連結,因為是使用非同步的方式在處理,所以也可以塞入多個連結給他

HtmlWeb client = new HtmlWeb();
client.LoadCompleted += client_LoadCompleted;
client.LoadAsync("http://astro.click108.com.tw/daily_10.php?iAstro=10");
client.LoadAsync("http://astro.click108.com.tw/daily_9.php?iAstro=9");
client.LoadAsync("http://astro.click108.com.tw/daily_8.php?iAstro=8");

 

然後透過註冊事件,並使用非同步的方式把你要解析的網頁填入,之後當他找到網頁時,便會執行你註冊的事件處理方法

private void client_LoadCompleted(object sender, HtmlDocumentLoadCompleted e)
{
            //Do parsing
}

現在我只要在此事件處理方法中寫上我要解析的程式碼即可,這邊我要解析上面那篇連結中的星座->水瓶座運勢中的星座名稱(也就是取得水瓶座名稱)與整體運勢

首先我們要先確定連線是否成功,在LoadCompleted方法中寫上下面此行

try
{
       if (e.Error == null)
       {
           HtmlDocument doc = e.Document;
           if (doc != null)
           {
                    //Parsing  
           }
         
      }
catch (Exception ex)
{
               Debug.WriteLine(ex.Message);
 }

做好Try Catch,並檢查連線是否Error,若沒有問題,我們再取得此網頁的Document做後續的解析

 

Parsing

如果上述的部分沒有問題的話,再來就是拿到前面的Document開始解析HTML囉

 

首先是擷取星座的名稱(這邊也就是水瓶座)

HtmlNodeCollection nameNodes = doc.DocumentNode.SelectNodes(@"//div[@class='ROOT']/p/a[2]");
 foreach (HtmlNode node in nameNodes)
 {
           string strValue = (node.InnerText).Substring(5);  //擷取字串
            Debug.WriteLine(strValue);
 }

 

上述中唯一的重點的就SelectNodes方法中帶的語法-XPath路徑語法,這邊解釋一下(用name當作節點)

//name

表示我要選擇「所有」是name的節點 ->所以//div表示我要選擇所有帶有div的節點

 

name[@key='value']

指定name中帶有key = value的節點->//div[@class='ROOT'] 表示說我要找出div中,屬性帶有class='ROOT'的節點

 

name1/name2

代表name2是name1中的子節點,所以 -> //div[@class='ROOT']/p/a 表示我要找出所有div中屬性帶有class='ROOT'且存在子節點有p,p的子節點有a的位置

 

name[number]

number代表同階層中的第幾個name節點,如上面的例子,p/a[2] 表示我要尋找p的子節點中的第2個a的節點,我想要拿到第2個a節點的資料,此時我便可以打上a[2]來鎖定到位置(number是從1開始,不要想成陣列index從0開始唷!~)

 

如下圖是HTML的節點階層

name_tag

 

因為前面提到//會拿取所有對應到我們下的XPath路徑的資料,所以可能會有多筆Node被我們找到,因此需要透過HtmlNodeCollection 類別來記錄所有找到的節點

然後一個個取出來。

 

再來我們要取得一開始提到的整體運勢(比對一開始的圖):

HtmlNodeCollection allFortuneContentNodes = doc.DocumentNode.SelectNodes(@"//div[@class='TODAY_CONTENT']/dt[@btype='all']/p");
foreach (HtmlNode node in allFortuneContentNodes)
{
         string strValue = (node.InnerText);
         Debug.WriteLine(strValue);
}

 

最後印出來的結果就會如下

html agility parsing

 

Parsing的程式碼:

 


 
private void client_LoadCompleted(object sender, HtmlDocumentLoadCompleted e)
        {            
            try
            {
                if (e.Error == null)
                {
                    HtmlDocument doc = e.Document;
                    if (doc != null)
                    {
                        Debug.WriteLine("connect ok");
                        //Get Name
                        Debug.WriteLine("Name:");
                        HtmlNodeCollection nameNodes = doc.DocumentNode.SelectNodes(@"//div[@class='ROOT']/p/a[2]");
                        foreach (HtmlNode node in nameNodes)
                        {
                            string strValue = (node.InnerText).Substring(5);
                            Debug.WriteLine(strValue);
                        }

                        
                        Debug.WriteLine("All:");
                        HtmlNodeCollection allFortuneContentNodes = doc.DocumentNode.SelectNodes(@"//div[@class='TODAY_CONTENT']/dt[@btype='all']/p");
                        foreach (HtmlNode node in allFortuneContentNodes)
                        {
                            string strValue = (node.InnerText);
                           
                            Debug.WriteLine(strValue);
                        }

                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }

 

 

 

結論

 


 

基本上之前在使用時,不同平台用的,裡面的一些功能可能不存在,或者是說名稱有換掉,所以各位在使用時可能要多研究研究

這邊是一個使用在WP上的範例,也是給若要使用在WP上的人可以快速了解的一篇文章,希望有幫助到~

 

參考資料

Why can't I use htmlagilitypack with windows phone 8? What else can I use to Parse HTML in WP8?

Wiki XPath

XML XPath的選擇節點語法

Xpath 語法 - 使用 HtmlAgilityPack 於 C#

Windows Phone 開發 - 使用 Html Agility Pack 取得統一發票資訊

 


 

文章中的敘述如有觀念不正確錯誤的部分,歡迎告知指正 謝謝 =)

另外要轉載請附上出處 感謝