Net处理html页面元素工具类(HtmlAgilityPack.dll)的使用

时间:2023-01-12 04:44:07

现在,在不少应用场合中都希望做到数据抓取,特别是基于网页部分的抓取。其实网页抓取的过程实际上是通过编程的方法,去抓取不同网站网页后,再进行 分析筛选的过程。比如,有的比较购物网站,会同时去抓取不同购物网站的数据并将其保存在数据库中。一般,这些网页的抓取都需要对抓取回来的HTML进行解 析。

.NET提供了很多类去访问并获得远程网页的数据,比如WebClient类和HttpWebRequest类。这些类对于利用HTTP去访问远端 的网页并且下载下来是很有用的,但在对于所下载下来的HTML的解析能力方面,则显得功能很弱了,以往,开发者不得不用很简陋的方法,比如使用 String.IndexOf,String.Substring或使用正则表达式去解析。

另外一种解析HTML的方法是使用开源的工具包HTML Agility Pack(http://htmlagilitypack.codeplex.com/),它的设计目标是尽可能简化对HTML文档的读和写。这个包本身 是利用了DOM文档对象模型去解析HTML的。仅需要几行代码,开发者就可以利用DOM 去访问文档中的头部一直到它的孩子结点。HTML Agility包也能通过XPATH去访问DOM中的指定结点,同时,它也包含了一个类可以用来下载远程网站上的网页,这意味者开发者可以利用它,同时下 载并且解析HTML网页了,十分方便。

本文将以几个例子展示如何使用HTML Agility包去下载和解析网页,代码例子在附件中可以下载。

准备工作

可以从http://htmlagilitypack.codeplex.com/)去下载Html Agility包,注意必须运行在ASP.NET 3.5及以后的版本上。下载后,这个工具包实际上是以HtmlAgilityPack.dll形式存在的。使用的时候,只需要将这个dll放在你的网站或 工程的bin目录下就可以了,我们目前使用的版本是1.4。

下面我们分别通过三个例子去说明如何使用HTML Agility。

例子一:列出远程网页的META标签

网页的抓取一般涉及到下载指定的网页,并且抓取指定的信息片断。第一个例子指导如何使用Html Agility包去下载一个网页,并且逐一循环显示出HTML页中的同时有名称和content标签的 标签中。

Html Agility Pack包包含了一些类,它们都在HtmlAgilityPack这个命名空间中,因此在使用前,先要引用这个命名空间,如下:

以下是代码片段:

using HtmlAgilityPack;

要从网站上去下载网页,可以使用HtmlWeb类的Load方法,当然实现要新建一个HtmlWeb的对象实例,如下:

以下是代码片段:

var webGet = new HtmlWeb();
var document = webGet.Load(url);

其中Load方法会返回一个HtmlDocument对象。在上面的代码中,我们把返回的HtmlDocument对象赋值到一个本地变量 document中去。HtmlDocument这个类代表了一个完整的HTML文档并且包含了DocumentNode属性,这个属性返回的是一个代表 文档根结点的HtmlNode对象。

HtmlNode类有几个属性,都十分简单,主要是用来遍历DOM的,包括:

  • ParentNode:访问父结点
  • ChildNodes:访问孩子结点
  • NextSibling:某个元素的下一个兄弟元素(也就是说同层次元素中的下一个元素)
  • PreviousSibling :某个元素的上一个兄弟元素(也就是说同层次元素中的上一个元素)

对于结点本身的判断,有如下属性:

  • Name - 获得或设置结点的名称。对HTML元素来说,它返回标签中的内容,比如对于BODY标签,则返回结果为”body ”,对于[P]标签则返回结果为”p ”,如此类推
  • Attributes -返回该元素的所有属性的集合
  • InnerHtml -返回或设置该元素中的HTML内容。
  • InnerText -返回结点的文本文字。
  • NodeType -指出结点的类型,可以是Document,Element,Comment或者是文本。

当然,也有很多其他的方法去获得指定的结点的信息,比如,Ancestors方法返回所有的祖先结点,而SelectNodes方法则返回匹配XPath表达式的结点集合。

有了这些方法和属性,现在我们就有很多方法去获得HTML文档中的所有 标签。这个例子中将采用SelectNodes方法。下面的语句调用了document对象的的DocumentNode属性中的SelectNodes 方法,使用了xpath表达式”//meta”,返回了所有文档中的 标记。

以下是代码片段:

var metaTags = document.DocumentNode.SelectNodes("//meta");

如果在文档中没有 标签,则metaTags变量会为null,如果有多于一个 标签,则metaTags会是一个HtmlNode的对象集合了,我们可以遍历并且显示它们的属性,如下代码:

以下是代码片段:

if (metaTags != null)
{
  foreach (var tag in metaTags)
  {
    if (tag.Attributes["name"] != null && tag.Attributes["content"] != null)
    {
    ... 输出 tag.Attributes["name"].Value 和 tag.Attributes["content"].Value ...
    }
  }
}

上面的代码中,首先使用了foreach去循环metaTags集合中的每个元素,然后判断每个元素的name和content属性的值是否为空,如果不空的话,直接输出其内容就可以了,看到了么,根本不需要用正则表达式,十分方便。

例子二 列出远程页面中的链接

上面的例子演示了如何使用SelectNodes方法和xpath去查找指定的结点。而另外一个方法是使用Linq的语法去实现。HtmlNode 类的方法,比如返回文档的祖先或者子孙结点的,实际上返回的都是象IEnumerable 的对象的,如果你对Linq语法熟悉,则知道Linq是很容易处理IEnumerable的,而且可以很容易使用Linq去查询HTML文档的结点。

为了演示如何使用Linq去访问结点,在这个例子中,将演示如何去获得某个页面的文本和所有超级链接(标签)的值。一开始的代码跟第一个例子是相同的,要创建HtmlWeb对象:

以下是代码片段:

var webGet = new HtmlWeb();
var document = webGet.Load(url);

标签中的,当然我们要求这些标签中是要内容的,不能只是空白,最后返回一个匿名类型,有两个属性:Url和Text:

接下来,将使用到document对象的Descendants方法和linq语法去获得指定页面的所有链接。准确的说,是获得页面中所有

以下是代码片段:

    var linksOnPage = from lnks in document.DocumentNode.Descendants()
      where lnks.Name == "a" &&
      lnks.Attributes["href"] != null &&
      lnks.InnerText.Trim().Length > 0
      select new
      {
        Url = lnks.Attributes["href"].Value,
        Text = lnks.InnerText
      };

看到了么,上面使用的正是LINQ语法。现在我们就可以使用一些asp.net的控件去展示这个linksOnPage中的内容了,本文代码中使用的是listview控件,命名为lvLinks: 以下是代码片段:

lvLinks.DataSource = linksOnPage;
lvLinks.DataBind();

前端的listbview变的简单了,如下: 以下是代码片段:

<asp:ListView ID="lvLinks" runat="server">
<LayoutTemplate>
<ul>
<asp:PlaceHolder runat="server" ID="itemPlaceholder" />
</ul>
</LayoutTemplate> 

<ItemTemplate>
<li>
<%# Eval("Text") %> - <%# Eval("Url") %>
</li>
</ItemTemplate>
</asp:ListView>

例子三 修改并保存HTML文档

上面两个例子分别演示了如何使用Html Agility包去抓取一个网页并且解析,但有的情况下,也需要修改文档的DOM结构并且保存到磁盘上。这个例子演示的跟前两个有点相象,要求用户输入一个网页的地址,之后抓取网页,并且对以下两个方面进行了修改。

  1. 在程序读取文档的同时,使用程序的方法,动态增加一个新的元素结点,使其成为标签的第一个孩子结点。
  2. 文档中所有的链接,改变成以新打开窗口的方式打开,这个设置其targer属性为_blank即可。

在修改完代码后,同时把它保存到用户本地的磁盘上。同样,一开始的步骤跟前面两个是一样的:

以下是代码片段:

var webGet = new HtmlWeb();
var document = webGet.Load(url);

接下来,通过Linq语法的扩展方法去查找body元素,下面的代码的意思是:在document结点的所有子孙结点中,查找第一个结点并且它的名称是“body”,如果不存在,则返回null。

以下是代码片段:

var body = document.DocumentNode.Descendants()
  .Where(n => n.Name == "body")
  .FirstOrDefault();

如果找到body标签后,我们则创建一个新的HTML元素标签,下面的代码创建了一个新的HTML元素标签(变量名为messageElement),并且指定了其样式属性,为这个标指定了其命名div,说明要创建的是一个

标签,最后为其指定了inner HTML属性的值,当然最后要把建立好的元素结点插入到body标签的开始:

以下是代码片段:

if (body != null)
{
var messageElement = new HtmlNode(HtmlNodeType.Element, document, 0);
messageElement.Attributes.Add("style", "width:95%;border:solid black 2px;background-color:#ffc;font-size:xx-large;text-align:center");
messageElement.Name = "div";
messageElement.InnerHtml = " Hello! This page was modified by the Html Agility Pack! Click on a link below... it should open in a new window! ";
body.ChildNodes.Insert(0, messageElement);
}

接下来,SelectNodes方法会返回所有

以下是代码片段:

var linksThatDoNotOpenInNewWindow = document.DocumentNode.SelectNodes("//a[@href]");
if (linksThatDoNotOpenInNewWindow != null)
{
  foreach (var link in linksThatDoNotOpenInNewWindow)
    if (link.Attributes["target"] == null)
      link.Attributes.Add("target", "_blank");
    else
      link.Attributes["target"].Value = "_blank";
}

最后,我们调用save方法去保存我们做的修改,在本文中,将其保存在ModifiedPages目录下,并且用guid的方法生成了其文件名,如下代码:

以下是代码片段:

var fileName = string.Format("~/ModifiedPages/{0}.htm", Guid.NewGuid().ToString());
document.Save(Server.MapPath(fileName));

下图显示了运行例子三后的结果,可以看到,我们把页面修改并保存后,在页面的一开始,的确加入了我们要加入的内容,并且你可以试下打开所有页面的链 接,都会发现是以新打开链接方式打开的,要注意的是,因为4guysfromrolla网页上使用的都是相对路径,因此图片我们这次没把它们保存下来,所 以在这个页面中看不到是正常的。

HTML解析组件HtmlAgilityPack使用

HtmlAgilityPack是一个开源的解析HTML元素的类库,最大的特点是可以通过XPath来解析HMTL,如果您以前用C#操作过XML,那么使用起HtmlAgilityPack也会得心应手。目前最新版本为1.4.6,下载地址如下:

http://htmlagilitypack.codeplex.com/

下 面以一个简单的例子来介绍下HtmlAgilityPack的使用,对于Asp.Net程序开发的网站要做模拟登录的时候,除了要知道用户名文本框和密码 文本框的name属性值外,还需要知道页面的__VIEWSTATE、__EVENTVALIDATION这两个隐藏控件的值,以及提交按钮的name属 性,下面看看怎样使用HtmlAgilityPack来获得这个额外的值。

1、在项目中添加对HtmlAgilityPack.dll的引用

Net处理html页面元素工具类(HtmlAgilityPack.dll)的使用

2、在Aspx页面中放几个文本框控件和一个按钮控件

Net处理html页面元素工具类(HtmlAgilityPack.dll)的使用

3、按钮的后台事件如下

protected void btnHtml_Click(object sender, EventArgs e)
        {
            if (tbUrl.Text.Length > 0)
            {
                HtmlWeb htmlWeb = new HtmlWeb();
                HtmlDocument htmlDoc = htmlWeb.Load(this.tbUrl.Text);
                HtmlNode htmlNode = htmlDoc.DocumentNode.SelectSingleNode("//input[@id='__VIEWSTATE']");
                string viewStateValue = htmlNode.Attributes["value"].Value;
                htmlNode = htmlDoc.DocumentNode.SelectSingleNode("//input[@id='__EVENTVALIDATION']");
                string eventValidation = htmlNode.Attributes["value"].Value;
                htmlNode = htmlDoc.DocumentNode.SelectSingleNode("//input[@type='submit']");
                string submitName = htmlNode.Attributes["name"].Value;

                tbViewState.Text = viewStateValue;
                tbEventValidation.Text = eventValidation;
                tbSubmitName.Text = submitName;
            }
        }

4、以博客园的登录界面为例,获取后的界面如下

Net处理html页面元素工具类(HtmlAgilityPack.dll)的使用

示例下载

Net处理html页面元素工具类(HtmlAgilityPack.dll)的使用

简介

本文介绍net处理html页面元素的工具类(HtmlAgilityPack.dll)的使用,用途比较多的应该是例如采集类的功能,采集到的html字符串要怎样处理是一个头痛的问题,如果是截取就太麻烦了而且容易出错。所有就用到本文的第三方dll来处理了。

下载

下载地址:http://htmlagilitypack.codeplex.com/

点击“download”按钮直接下载。

使用

1.添加HtmlAgilityPack.dll引用(引用类using HtmlAgilityPack;)。

2.简单根据html中input的id获取value代码如下:

Net处理html页面元素工具类(HtmlAgilityPack.dll)的使用
// 模拟用户请求
WebClient webClient = new WebClient();
webClient.Encoding = System.Text.Encoding.UTF8;
string htmlContext = webClient.DownloadString("http://stone_w.cnblogs.com/");
webClient.Credentials = CredentialCache.DefaultCredentials; // 添加授权证书
webClient.Headers.Add("User-Agent", "Microsoft Internet Explorer");
webClient.Headers.Add("Host", "www.cnblogs.com");

// 获取html元素(htmlContext为html页面字符串)
HtmlDocument htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(htmlContext);  // 加载html页面
HtmlNode navNode = htmlDoc.GetElementbyId("id名称");
Response.Write(navNode.Attributes["value"].Value);
Net处理html页面元素工具类(HtmlAgilityPack.dll)的使用

总结

HtmlAgilityPack可以根据id查询value,还可以获取单个元素节点,都是HtmlDocument类的内置方法,大家可以试着练练。谢谢完~

Net处理html页面元素工具类(HtmlAgilityPack.dll)的使用的更多相关文章

  1. 处理html页面元素工具类&lpar;HtmlAgilityPack&period;dll&rpar;的使用

    下载地址:http://htmlagilitypack.codeplex.com/ 1.添加HtmlAgilityPack.dll引用(引用类using HtmlAgilityPack;). 2.简单 ...

  2. 生成freemarker静态页面的工具类

    package cn.bocai.pc.util; import java.io.BufferedWriter;import java.io.File;import java.io.FileOutpu ...

  3. 微软拼音转换工具类ChnCharInfo&period;dll

    1.简介 之前做汉字转拼音是使用各种枚举的方式,将各种情况列举,这种方式出错的机率很大,经常对不上号.(如果你想了解更多:http://www.cnblogs.com/islands/articles ...

  4. HtmlAgilityPack&period;dll的使用 获取HTMLid

    简介 本文介绍net处理html页面元素的工具类(HtmlAgilityPack.dll)的使用,用途比较多的应该是例如采集类的功能,采集到的html字符串要怎样处理是一个头痛的问题,如果是截取就太麻 ...

  5. Java—集合工具类

    集合中的元素工具类排序: Java提供了一个操作Set.List和Map等集合的工具类:Collections,该工具类提供了大量方法对集合进行排序.查询和修改等操作,还提供了将集合对象置为不可变.对 ...

  6. Android工具类整合

    Android-JSONUtil工具类 常用的Json工具类,包含Json转换成实体.实体转json字符串.list集合转换成json.数组转换成json public class JSONUtil ...

  7. Android两个页面之间的切换效果工具类

    import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; ...

  8. 【自制工具类】Java删除字符串中的元素

    这几天做项目需要把多个item的id存储到一个字符串中,保存进数据库.保存倒是简单,只需要判断之前是否为空,如果空就直接添加,非空则拼接个"," 所以这个字符串的数据结构是这样的 ...

  9. TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort&lpar;&rpar;方法如何比较元素?

    TreeSet要求存放的对象所属的类必须实现Comparable接口,该接口提供了比较元素的compareTo()方法,当插入元素时会回调该方法比较元素的大小.TreeMap要求存放的键值对映射的键必 ...

随机推荐

  1. 忘记mysql root 密码修改小技巧

    首先我说一下我的情况,我并不是忘记了我的root密码,只不过是我在使用phpmyadmin的时候更改密码的时候选择了如图1 的这个方法将密码加密并更改了,然后就再次登录的时候登录不上,所以对于菜鸟级的 ...

  2. 51nod1088&lpar;最长回文子串&rpar;

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1088 题意: 中文题目诶~ 思路: 这道题字符串长度限定为1 ...

  3. 禁止root远程登录

    Linux禁止root远程登录 ssh的修改vi /etc/ssh/sshd_config将默认的#PermitRootLogin yes去注释改为PermitRootLogin no service ...

  4. Codeforces Round &num;364 &lpar;Div&period; 2&rpar; E&period; Connecting Universities &lpar;DFS&rpar;

    E. Connecting Universities time limit per test 3 seconds memory limit per test 256 megabytes input s ...

  5. 浅谈cookie,sessionStorage和localStorage

    cookie:cookie在浏览器和服务器间来回传递 cookie数据不能超过4k 同时每次http请求都会携带cookie,所以cookie只适合保存很小的数据,比如会话标识 cookie只在设置的 ...

  6. kmp算法:

    自学kmp算法: first time:wa #include<cstdio> #include<algorithm> #include<iostream> #in ...

  7. 关于Axure RP软件的介绍——软件工程实践第二次个人作业

    关于Axure RP软件的介绍——软件工程实践第二次个人作业 Axure RP是一个非常专业的快速原型设计的一个工具,客户提出需求,然后根据需求定义和规格.设计功能和界面的专家能够快速创建应用软件或W ...

  8. SFTP多文件上传&comma;删除

    公司项目中需要把项目的相关文件上传到服务器的tomcat中,需要在项目中进行以下几步操作: 1.添加项目信息,包括名称,描述,服务器ip,sftp的用户名,密码,端口号等,存在配置,部署,删除等操作 ...

  9. Java的checked exception与unchecked exception

    在Java中exception分为checked exception和unchecked异常,两者有什么区别呢? 从表象来看, checked异常就是需要在代码中try ... catch ...的异 ...

  10. NHibernate之配置文件属性说明

    一.NHibernate配置所支持的属性 属性名 用途 dialect 设置NHibernate的Dialect类名 - 允许NHibernate针对特定的关系数据库生成优化的SQL 可用值: ful ...