.NET使用Html Agility Pack解析html
.NET使用Html Agility Pack解析html在不少应用场合中都希望做到数据抓取,特别是基于网页部分的抓取。其实网页抓取的过程实际上是通过编程的方法,去抓取不同网站网页后,再进行分析筛选的过程。比如,有的比较购物网站,会同时去抓取不同购物网站的数据并将其保存在数据库中。一般,这些网页的抓取都需要对抓取回来的HTML进行解析。
.NET提供了很多类去访问并获得远程网页的数据,比如WebClient类和HttpWebRequest类。这些类对于利用HTTP去访问远端的网页并且下载下来是很有用的,但在对于所下载下来的HTML的解析能力方面,以往,开发者不得不用很简陋的方法,比如使用String.IndexOf,String.Substring或使用正则表达式去解析。
一种方便有效解析HTML的方法是使用开源的工具包HTML Agility Pack,这个包本身是利用了DOM文档对象模型去解析HTML的。仅需要几行代码,开发者就可以利用DOM 去访问文档中的头部一直到它的孩子结点。HTML Agility包也能通过XPATH去访问DOM中的指定结点,同时,它也包含了一个类可以用来下载远程网站上的网页,这意味者开发者可以利用它,同时下载并且解析HTML网页了,十分方便。
一、下载和引用
可以从 http://htmlagilitypack.codeplex.com/ 去下载Html Agility包,下载后,这个工具包实际上是以HtmlAgilityPack.dll形式存在的。使用的时候,只需要将这个dll放在你的网站或工程的bin目录下就可以了。
二、Html Agility Pack的使用
1、Html Agility Pack包包含了一些类,它们都在HtmlAgilityPack这个命名空间中,因此在使用前,先要引用这个命名空间,using HtmlAgilityPack
2、Html Agility Pack解析html是基于HtmlDocument对象,HtmlDocument这个类代表了一个完整的HTML文档并且包含了DocumentNode属性,这个属性返回的是一个代表文档根结点的HtmlNode对象,我们可以在这个根结点的HtmlNode对象的基础上通过SelectNodes、SelectSingleNode以XPath表达式的方式获取其它节点。
3、结点有如下几个重要属性
Name - 获得或设置结点的名称。对HTML元素来说,它返回标签中的内容,比如对于BODY标签,则返回结果为”body ”,对于[P]标签则返回结果为”p ”,如此类推
Attributes -返回该元素的所有属性的集合
InnerHtml -返回或设置该元素中的HTML内容。
InnerText -返回结点的文本文字。
NodeType -指出结点的类型,可以是Document,Element,Comment或者是文本。
三、Html Agility Pack的实例
1、解析如下Html页面,获取文章列表
2、定义如下实体
using System;
namespace MessageHelper
{
public class Model
{
public string Title { get; set; } //标题
public string Content { get; set; } //内容
public string Href { get; set; } //文章链接
public string ComeFrom { get; set; } //来源
public DateTime Time { get; set; } //发布时间
}
}
3、定义解析Html的XPath变量
/// <summary>
/// 获取文章列表
/// </summary>
private const string MessageListXPath = "//li[starts-with(@class,'list_item article_item')]";
(2)、下面这句话是 获取上面获取出来的集合里面每一项的标题
/// <summary>
/// 获取标题 解释: 第一个li,下的第一个li,下的第一个h1,下的第一个span,下的第一个a标签
/// </summary>
private const string MessageNameXPath = "/li[1]/li[1]/h1[1]/span[1]/a[1]";
(3)、和上面一样这个是获取内容
/// <summary>
/// 获取内容 解释: 第一个li,下的第二个li
/// </summary>
private const string MessageContxtXPath = "/li[1]/li[2]";
(4)、这个是获取发布时间
/// <summary>
/// 获取时间 这个就是 获取 第一个li,下的第3个li,下的span
/// </summary>
private const string MessageTimeXPath = "/li[1]/li[3]/span";
4、用 Html Agility Pack 找出我们想要的东西
/// <summary>
/// 处理文章信息 Add shuaibi 2015-03-08
/// </summary>
/// <param name="myStream">网页的数据流</param>
/// <returns></returns>
private static List<Model> GetMessage(Stream myStream)
{
var document = new HtmlDocument();
document.Load(myStream, Encoding.UTF8);
var rootNode = document.DocumentNode;
var messageNodeList = rootNode.SelectNodes(MessageListXPath);
return messageNodeList.Select(messageNode => HtmlNode.CreateNode(messageNode.OuterHtml)).Select(temp => new Model
{
Title = temp.SelectSingleNode(MessageNameXPath).InnerText,
Href = "http://blog.csdn.net" + temp.SelectSingleNode(MessageNameXPath).Attributes["href"].Value,
Content = temp.SelectSingleNode(MessageContxtXPath).InnerText,
Time = Convert.ToDateTime(temp.SelectSingleNode(MessageTimeXPath).InnerText),
ComeFrom = "csdn"
}).ToList();
}
5、获网页的Html并调用解析Html的方法
/// <summary>
/// 获取文章列表 Add shuaibi 2015-03-08
/// </summary>
/// <param name="url">页面地址</param>
/// <returns>文章列表</returns>
public List<Model> GetHtml(string url)
{
var myWebClient = new WebClient();
var myStream = myWebClient.OpenRead(url);
var list = GetMessage(myStream); //这里调用的是上面定义的方法
if (myStream != null) myStream.Close();
return list;
}