[Windows Phone/C#] C# 网页撷取数据 解析网页标签(HTML Parser )API -HTML Agility Pack 以Windows Phone 8 为例

有时候我们会需要开发一些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 SDKsMicrosoft SDKsSilverlightv4.0LibrariesClient

或是

ProgramFiles%Microsoft SDKsMicrosoft SDKsSilverlightv4.0LibrariesClient

可以找到

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 取得统一发票资讯


文章中的叙述如有观念不正确错误的部分,欢迎告知指正 谢谢 =)

另外要转载请附上出处 感谢