如今愈来愈多的场景须要咱们使用网络爬虫,抓取相关数据便于咱们使用,今天咱们要讲的主角Html Agility Pack是在爬取的过程中,可以高效的解析咱们抓取到的html数据。html
在.NET技术下,解析html工具也不少,好比不少人可能会使用htmlparser,或者微软的MSHTML,htmlparser虽然比较易上手,可是相对应的解析速度较慢,而Html Agility Pack解析速度至关快,而且开源,易用,它能够帮助咱们解析html文档就像用XmlDocument类来解析xml同样轻松、方便。node
传送门:官网地址,Github开源代码地址git
其实Html Agility Pack的类不是不少,咱们解析Html的时候,用到的也就HtmlDocument和HtmlNode(还有HtmlNodeCollection集合类)这几个类。官网也有相对应的API文档说明,其实真的是简单易懂,传送门:API文档github
Question 一、如何加载Html?web
HtmlDocument类定义; 多个重载Load方法来实现不一样方式的Html加载,主要常见的有三种方式;从文件加载、从字符串加载、从网页连接加载。api
示例:网络
1 // 从物理路径的文件加载 2 var doc = new HtmlDocument(); 3 doc.Load(filePath);//文件路径 4 5 // 从Stream当中加载 6 var doc = new HtmlDocument(); 7 doc.LoadHtml(html); 8 9 // 从网页的Url连接加载 10 var url = "http://www.cnblogs.com/xuliangxing/"; 11 var web = new HtmlWeb(); 12 var doc = web.Load(url);
以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) ///缓冲区大小
以指定的物理路径为主的重载方法:post
(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)
Question 二、如何精准定位到咱们须要的数据?ui
这个时候咱们须要用到HtmlNodeCollection和HtmlNode这两个类,咱们把Html每一个标签看做一个Node,全部咱们想到定位到某个标签的内容,就须要知道这个标签的相关属性。顺便说一下,HtmlNode类实现了IXPathNavigable接口,这说明了它能够经过xpath来定位数据了,若是你对解析XML格式数据的XmlDocument类了解的话,特别是使用过了SelectNodes()和SelectSingleNode()方法的人来讲,对使用HtmlNode类将会很熟悉。其实Html Agility Pack内部是把html解析成xml文档格式了的,因此支持xml中的一些经常使用查询方式。下面经过简单示例对HtmlNode的一些主要的经常使用成员做简要的说明。
就以我博客园主页为例,但愿你们在此基础上可以触类旁通,这里只作抛砖引玉,界面图以下:
后台Html代码,我抓取了部分代码拿来作示例
1 <!DOCTYPE html> 2 <html lang="zh-cn"> 3 <head> 4 <meta charset="utf-8"/> 5 <meta name="viewport" content="width=device-width, initial-scale=1" /> 6 <title>法号阿兴 - 博客园</title> 7 </head> 8 <body> 9 <div id="home"> 10 <div id="header"> 11 <div id="blogTitle"> 12 <a id="lnkBlogLogo" href="http://www.cnblogs.com/xuliangxing/"><img id="blogLogo" src="/Skins/custom/images/logo.gif" alt="返回主页" /></a> 13 <h1><a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/xuliangxing/">法号阿兴</a></h1> 14 <h2>你的能力还驾驭不了你的目标时,就应该沉下心来历练</h2> 15 </div> <!--end: blogTitle 博客的标题和副标题 --> 16 <div id="navigator"> 17 <ul id="navList"> 18 <li><a id="blog_nav_sitehome" class="menu" href="http://www.cnblogs.com/">博客园</a></li> 19 <li><a id="blog_nav_myhome" class="menu" href="http://www.cnblogs.com/xuliangxing/">首页</a></li> 20 <li><a href="http://news.cnblogs.com/">新闻</a></li> 21 <li><a id="blog_nav_newpost" class="menu" rel="nofollow" href="https://i.cnblogs.com/EditPosts.aspx?opt=1">新随笔</a></li> 22 <li><a id="blog_nav_contact" accesskey="9" class="menu" rel="nofollow" href="https://msg.cnblogs.com/send/%E6%B3%95%E5%8F%B7%E9%98%BF%E5%85%B4">联系</a></li> 23 <li><a id="blog_nav_admin" class="menu" rel="nofollow" href="https://i.cnblogs.com/">管理</a></li> 24 <li><a id="blog_nav_rss" class="menu" href="http://www.cnblogs.com/xuliangxing/rss">订阅</a> 25 <a id="blog_nav_rss_image" class="aHeaderXML" href="http://www.cnblogs.com/xuliangxing/rss"><img src="//www.cnblogs.com/images/xml.gif" alt="订阅" /></a></li> 26 </ul> 27 </div><!--end: header 头部 --> 28 <div id="main"></div><!--end: 正文 --> 29 <div id="footer"></div><!--end: 底部 --> 30 </div> 31 </body> 32 </html>
通常Html最多见的是div标签元素,它可能会定义一些属性,比例本文当中的<div id="blogTitle">,有些不是id属性,是class属性,这个根据实际状况而定,要灵活变通
(1)经过ID属性(或者其余属性)来选择对应的节点
通用格式:@id=‘xxxx’(id能够是其余属性等等),好比咱们要定位到本文博客主页的标题和副标题内容。
1 HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument(); 2 doc.LoadHtml(url)//博客主页URL 3 //下面的意思是:经过属性id的值,来定位header下的blogTitle节点信息 4 HtmlNode titleNode = doc.DocumentNode.SelectSingleNode("//div[@id='header']/div[@id='blogTitle']");
咱们还能够不经过属性id去定位,还有经过索引去定位,以下所示,这个效果和上面是等同的:
1 //下面的意思是:经过索引定位,div[2]是表示根节点的第二个 2 HtmlNode titleNode = doc.DocumentNode.SelectSingleNode("//div[2]/div[1]");
备注:注意路径里"//"表示从根节点开始查找,两个斜杠‘//’表示查找全部childnodes;一个斜杠'/'表示只查找第一层的childnodes(即不查找grandchild);点斜杠"./"表示从当前结点而不是根结点开始查找。咱们接着上面titleNode节点,查找我博客园的ID。
1 //下面的意思是:经过当前titleNode节点,获取便签h1的节点 2 HtmlNode IDNode = titleNode.SelectSingleNode("./h1");
讲解了上面这些,你们应该已经可以明白了Html Agility Pack的基本使用方法,那么如何一次性获取博主的ID呢?
1 HtmlNode IDNode = doc.DocumentNode.SelectSingleNode("//div[@id='header']/div[@id='blogTitle']/h1");
(2)如何获取节点文本内容
接着上面(1)所说的,经过代码“HtmlNode IDNode = doc.DocumentNode.SelectSingleNode("//div[@id='header']/div[@id='blogTitle']/h1") ”获取到了IDNode的节点,那么接下来,咱们须要这么获取具体的文本值呢(即博主ID)?有三种方式获取OuterHtml,InnerHtml和InnerText。
HtmlNode类设计了OuterHtml属性和InnerHtml属性用于获取当前节点的Html源码。二者不一样之处是,OuterHtml属性返回的是包含当前节点的Html代码在内的全部Html代码,而InnerHtml属性返回的是当前节点里面子节点的全部Html代码,InnerText属性过滤掉了全部的Html标记代码,只返回文本值。具体用哪一种方式,要根据咱们实际状况而定,通常InnerHtml和InnerText使用的频率比较多。以下所示:
1 //咱们获取博客ID 2 IDNode.OuterHtml ///返回结果是:<h1><a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/xuliangxing/">法号阿兴</a></h1> 3 IDNode.InnerHtml ///返回结果是:<a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/xuliangxing/">法号阿兴</a> 4 IDNode.InnerText ///返回结果是:法号阿兴
(3)如何获取节点属性值
假如咱们上面Html数据当中,博主博客地址,在标签<div id="header">里的<a>标签里,这个时候就须要使用HtmlNode下的Attribute属性了。
1 string url = doc.DocumentNode.SelectSingleNode("//div[@id='header']/div[@id='blogTitle']/a").Attributes["href"].Value;
(4)如何获取某个标签的全部节点
咱们若是获取前面Html数据的li全部分类,这个时候须要使用方法SelectNodes了
HtmlNodeCollection uiListNodes = doc.DocumentNode.SelectNodes("//ui[@id='navList']/li");
Question 三、Html Agility Pack进行删除操做
Html Agility Pack是能够对Html作删除操做的,具体的能够参考官网的API,这里咱们讲下最多见
(1)如何去掉外层的html tag只留下文本内容
回到咱们刚刚上面讲到的地方,用remove方法。假设要删除上文结点<a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/xuliangxing/">法号阿兴</a>,你想留下博客名称而不要<a></a>的话,那你须要先获得这个Html结点,经过remove方法删除掉多余的HTML Tag假设该节点叫Node:
Node.ParentNode.RemoveChild(Node,true);
参数true表示留下grandchild,在这里即博主博客ID内容; false表示将此结点连同其grandchilds一块儿删除。
更多的方法你们能够到官网的API文档进行了解,这里就不作更多的说明。
PS:若有疑问,请留言,未经容许,不得私自转载,转载请注明出处:http://www.cnblogs.com/xuliangxing/p/8004403.html