HTML解析神器--HtmlAgilityPack

Html Agility Pack是codeplex里的一款开源库(http://htmlagilitypack.codeplex.com/),是一个灵活的html解析器,支持通过简单XPATH 或 XSLT来读和写DOM,最新版本已经支持LINQ。对开发网络爬虫,网络数据挖掘等方面Html Agility Pack能够提供很多功能上的支持。

 

 

参考地址:http://www.cnblogs.com/ITmuse/archive/2010/05/29/1747199.html

基础类和基础方法介绍

Html Agility Pack最常用的基础类其实不多,对解析DOM来说,就只有HtmlDocument和HtmlNode这两个常用的类,还有一个 HtmlNodeCollection集合类。

 

HtmlDocument类

当然在解析DOM前需要加载html原始文件或者html的字符串,HtmlDocument类封装了支持此功能的方法,下面是加载html的方法介绍。


HtmlDocument类定义了多个重载的Load方法来实现以不同方式加载html,其实主要分为两种,一种是从Stream中加载html,另外一种是从物理路径加载html,分别见下面:


方法:public void Load(TextReader reader)
说明:从指定的 TextReader对象中加载Html
示例

 

 
   
HtmlDcument doc = new HtmlDocument();

StreamReader sr
= File.OpenText( " file path " );

doc.Load(sr);

 

 

 


基于上面方法,衍生出了几个不同重载方法。

以指定的Stream对象为主的有:

(1)public void Load(Stream stream)    ///从指定的Stream对象中加载html;

(2)public void Load(Stream stream, bool detectEncodingFromByteOrderMarks)    ///指定是否从顺序字节流中解析编码格式

(3)public void Load(Stream stream, Encoding encoding)    ///指定编码格式

(4)public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)

(5)public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)


以指定的物理路径为主的有:

 (1)public void Load(string path)

(2)public void Load(string path, bool detectEncodingFromByteOrderMarks)    ///指定是否从顺序字节流中解析编码格式

(3)public void Load(string path, Encoding encoding)    ///指定编码格式

(4)public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)

(5)public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)

 

HtmlDocument类中还定义了直接从html字符串中加载Html,如下:


方法:public void LoadHtml(string html)
说明:从指定的html字符串中加载html
示例

 

 
   
HtmlDocument doc = new HtmlDocument();

string html = "
" demo " > " color:red; " >

Hello World!

" ;

doc.LoadHtml(html);

 

 

 


HtmlDocument类还有其他写DOM方法的定义,这里不作详细介绍,留作以后专门介绍Html Agility Pack写DOM章节介绍吧,这里着重介绍Html Agility pack解析DOM的细节。

 

HtmlNode类和HtmlNodeCollection类


通过HtmlDocument把html加载进来后,接着是要做什么呢?当然是对html解析了,解析DOM就需要提到HtmlNode类了。 HtmlDocument类由属性DocumentNode属性返回当前Html解析后的一个全局的HtmlNode对象;如果想获取某一个元素的 HtmlNode,可以通过HtmlDocument类的GetElementbyId(string Id)方法来获取,返回指定某一个html元素的HtmlNode对象。如何通过HtmlNode对象来访问DOM呢?介绍之前先对它的功能了解下。


HtmlNode类实现了IXPathNavigable接口,这说明了它可以通过xpath来查询DOM了,如果对System.Xml命名空间下的 XmlDocument类了解的,特别是使用过了SelectNodes()和SelectSingleNode()方法的朋友对使用HtmlNode类将会很熟悉。其实Html Agility Pack内部是把html解析成xml文档格式了的,所以支持xml中的一些常用查询方式。下面对HtmlNode的一些主要的常用成员作简要的说明。

 

HtmlNode类的主要属性

1)Attributes属性

获取当前Html元素的属性的集合,返回的是一个HtmlAttributeCollection对象。如一个div元素,它可能会定义一些属性,如:

***
,那Attributes返回的HtmlAttributeCollection就包含了 “id,name,class,title”的信息。HtmlAttributeCollection类是实现了接口 IList的一个集合类,故此可以通过下面代码方式访问每一个成员。

 

 
   
HtmlNode node = doc.GetElementbyId( " title " );

string titleValue = node.Attributes[ " title " ].Value;

 

 


或者

 

 

复制代码
 
   
foreach (HtmlAttribute attr in node.Attributes)

{

Console.WriteLine(
" {0}={1} " ,attr.Name,attr.Value);

}
复制代码

 

 


在获取属性值时,如果某一个属性名称不存在的话,Attributes["name"]返回的是null值。


2)FirstChild,LastChild,ChildNodes,ParentNode属性


FirstChild属性:返回所有子节点的第一个节点,如下面代码:


 

 
   
string html = "
" demo " > " color:red; " >

Hello World!

" innerDiv " >inner div
" ;

 

 

 

 

FirstChild则返回的是“

Hello World!

” 的节点。


LastChild属性:返回所有子节点的最后一个节点,以上面的html为例,则返回“

inner div
”节点。


ChildNodes属性:返回当前节点所有直接一代的子节点的集合,不包括跨代子节点,以上面的html为例,则返回“

Hello World!

” 和“
inner div
”两个节点。


ParentNode属性:返回当前节点的直接父节点。

 

3)获取Html源码和文本


HtmlNode类设计了OuterHtml属性和InnerHtml属性用于获取当前节点的Html源码。两者不同之处是,OuterHtml属性返回的是包含当前节点的Html代码在内的所有Html代码,而InnerHtml属性返回的是当前节点里面子节点的所有Html代码。如下面:

 

 

代码

 

 


如要获取节点的文本值,通过InnerText属性来获取,InnerText属性过滤掉了所有的Html标记代码,只返回文本值,如下面:


 

 
   
Console.WriteLine(node.InnerText); /// return "Hello World!";

 

 

 

 

HtmlNode类的主要方法

HtmlNode类提供了足够丰富的方法供查询当前节点下的子节点(元素),当然也包括查询当前节点的父节点(元素)的方法,下面列出主要的方法和使用说明。


获取父节点的系列方法:

1)public IEnumerable Ancestors()

获取当前节点的父节点列表(不包含自身)。

2)public IEnumerable Ancestors(string name)

以指定一个名称来获取父节点的列表(不包含自身)。

3)public IEnumerable AncestorsAndSelf()

获取当前节点的父节点列表(包含自身)。

4)public IEnumerable AncestorsAndSelf(string name)

以指定一个名称来获取父节点的列表(包含自身)。

获取子节点的系列方法:

1)public IEnumerable DescendantNodes()

获取当前节点下的所有子节点的列表,包括子节点的子节点(不包含自身)。

2)public IEnumerable DescendantNodesAndSelf()

获取当前节点下的所有子节点的列表,包括子节点的子节点(包含自身)。

3)public IEnumerable Descendants()

获取当前节点下的直接子节点的列表(不包含自身)。

4)public IEnumerable DescendantsAndSelf()

获取当前节点下的直接子节点的列表(包含自身)。

5)public IEnumerable Descendants(string name)

获取当前节点下的以指定名称的子节点列表。

6)public IEnumerable DescendantsAndSelf(string name)

获取当前节点下的以指定名称的子节点的列表(包含自身)。

7)public HtmlNode Element(string name)

获取第一个符合指定名称的直接子节点的节点元素。

8)public IEnumerable Elements(string name)

获取符合指定名称的所有直接子节点的节点列表。

9)public HtmlNodeCollection SelectNodes(string xpath)

获取符合指定的xpath的子节点列表。

10)public HtmlNode SelectSingleNode(string xpath)

获取符合指定的xpath的单个字节点元素。


查询节点的方法主要是上面10个方法,该类还有其他写节点的系列方法,这里不详细介绍写操作的方法,留作以后详细介绍。

结合Xpath进行查询节点是功能比较强大,这像操作xml那样方便。


简单例子的代码

下面例子是把博客园的精华区博客列表查询出来。执行结果如下面:

 HTML解析神器--HtmlAgilityPack_第1张图片


代码

 

复制代码
代码
 
    
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using HtmlAgilityPack;


namespace DemoCnBlogs
{
class Program
{
static void Main( string [] args)
{
HtmlWeb web
= new HtmlWeb();
HtmlDocument doc
= web.Load( " http://www.cnblogs.com/pick/ " );

HtmlNode node
= doc.GetElementbyId( " post_list " );

StreamWriter sw
= File.CreateText( " log.txt " );

foreach (HtmlNode child in node.ChildNodes)
{
if (child.Attributes[ " class " ] == null || child.Attributes[ " class " ].Value != " post_item " )
continue ;
HtmlNode hn
= HtmlNode.CreateNode(child.OuterHtml);

/// 如果用child.SelectSingleNode("//*[@class=\"titlelnk\"]").InnerText这样的方式查询,是永远以整个document为基准来查询,
/// 这点就不好,理应以当前child节点的html为基准才对。

Write(sw, String.Format(
" 推荐:{0} " , hn.SelectSingleNode( " //*[@class=\ " diggnum\ " ] " ).InnerText));
Write(sw, String.Format(
" 标题:{0} " , hn.SelectSingleNode( " //*[@class=\ " titlelnk\ " ] " ).InnerText));
Write(sw, String.Format(
" 介绍:{0} " , hn.SelectSingleNode( " //*[@class=\ " post_item_summary\ " ] " ).InnerText));
Write(sw, String.Format(
" 信息:{0} " , hn.SelectSingleNode( " //*[@class=\ " post_item_foot\ " ] " ).InnerText));

Write(sw,
" ---------------------------------------- " );

}

sw.Close();

Console.ReadLine();
}

static void Write(StreamWriter writer, string str)
{
Console.WriteLine(str);
writer.WriteLine(str);
}


}
}
复制代码

 

 

 

你可能感兴趣的:(HTML解析神器--HtmlAgilityPack)