HtmlAgilityPack的一点总结
2013-12-21 21:33
260 查看
最近工作中用到了HtmlAgilityPack的类库,总的来说使用起来确实感觉挺方便,别的不多说,就这类似于能把HTML标签自动补全的Load()方法就感觉挺赞(其实上不是不全,而是将不完整的标签给格式化一下)。但这不就足够了吗?舍得自己去用正则表达式去匹配,万一匹配的内容就是HTML作者写的文本内容,岂不功亏一篑。
不废话,使用的时候加载HtmlAgilityPack.dll(下载去官网),using HtmlAgilityPack; 就可以使用[b]HtmlAgilityPack了。[/b]
本文以格式化一篇Html为例,讲述一点此类库的一点用法,至于更多的方法和属性,那就看作者的发挥了。
何为格式化HTML?当你看到别人写的HTML是这样的:
<html><head><title>就是一个字符串</title></head><body><p>就是不换行</p></body></html>
是不是觉得很头疼呢?写成规范一点的树结构是不是更好一点?(虽然改变了原文,加入了很多/r,/n,/t,但毕竟这是用户想看到的)
[b]<html>[/b]
[b]______<head>[/b]
[b]______[b]______[/b][/b]<title>
______[b]______[b]______[/b][/b]就是一个字符串
[b]______[b]______[/b][/b]</title>
______</head>
______<body>
[b]______[b]______[/b][/b]<p>
______[b]______[b]______[/b][/b]就是不换行
[b]______[b]______[/b][/b]</p>
[b][b]______[/b][/b]</body>
</html>
当然了,强大的IDE和各种工具会帮你做到,但是!实际开发中怎会容你轻松的使用其他非开源工具,而开元的HTMLAgility区区几行代码便能做到。
不多说,上代码:
不废话,使用的时候加载HtmlAgilityPack.dll(下载去官网),using HtmlAgilityPack; 就可以使用[b]HtmlAgilityPack了。[/b]
本文以格式化一篇Html为例,讲述一点此类库的一点用法,至于更多的方法和属性,那就看作者的发挥了。
何为格式化HTML?当你看到别人写的HTML是这样的:
<html><head><title>就是一个字符串</title></head><body><p>就是不换行</p></body></html>
是不是觉得很头疼呢?写成规范一点的树结构是不是更好一点?(虽然改变了原文,加入了很多/r,/n,/t,但毕竟这是用户想看到的)
[b]<html>[/b]
[b]______<head>[/b]
[b]______[b]______[/b][/b]<title>
______[b]______[b]______[/b][/b]就是一个字符串
[b]______[b]______[/b][/b]</title>
______</head>
______<body>
[b]______[b]______[/b][/b]<p>
______[b]______[b]______[/b][/b]就是不换行
[b]______[b]______[/b][/b]</p>
[b][b]______[/b][/b]</body>
</html>
当然了,强大的IDE和各种工具会帮你做到,但是!实际开发中怎会容你轻松的使用其他非开源工具,而开元的HTMLAgility区区几行代码便能做到。
不多说,上代码:
private HtmlDocument loadWebSi b471 te(string path) { HtmlDocument hDoc = new HtmlDocument();//整片html文档对象 if (File.Exists(path)) { hDoc.Load(path, Encoding.Default); hDoc.LoadHtml(hDoc.DocumentNode.OuterHtml);//load两边是为了保证标签的完整性,DocumentNode代表文档节点 (文档的开头了结尾,不一定是<html>,OuterHtml代表此nod e的html文本) } return hDoc; }计算父节点的方法,以<html>节点为根父节点,有所少个父节点,就加入多少个/t(缩进)
private int parentNumbers(HtmlNode node, int temp) { int result = temp; if (node.ParentNode != null) { if (node.ParentNode.Name.Equal("html")) { return result; } else { result = result + parentNumbers(node.ParentNode, 1);//递归调用 } } return result; }好了,以上两个方法是准备工作,真正格式化的方法在这里:
private void convertHTML(string filePath) { HtmlDocument hDoc = loadWebSite(filePath); string reg = "\\S+"; Regex regex = new Regex(reg, RegexOptions.IgnoreCase);//此处的正则表达式是为了将html文件写成一行,将原作者的转义字符取消,加入自己的转义字符(/r/n/t) HtmlNodeCollection htmlNodeCollection = hDoc.DocumentNode.SelectNodes("/html"); StringBuilder htmlContent = new StringBuilder(); if (htmlNodeCollection.Count() > 0) { foreach (HtmlNode htmlNode in htmlNodeCollection) { foreach (HtmlNode hNode in htmlNode.Descendants().Where(n => n.NodeType == HtmlNodeType.Text)) { Match match = regex.Match(hNode.OuterHtml); if (match.Success == false) { hNode.InnerHtml = string.Empty; } else { hNode.InnerHtml = hNode.InnerHtml.Trim(); } } htmlContent.Append(htmlNode.OuterHtml); } } else { throw new Exception("Document Have No Html Element"); } //load两遍,保证标签的完整性 hDoc.LoadHtml(htmlContent.ToString()); StringBuilder content = new StringBuilder(hDoc.DocumentNode.OuterHtml); hDoc.LoadHtml(content.ToString()); HtmlNodeCollection lineCollection = hDoc.DocumentNode.SelectNodes("/html"); Dictionary<int, string> insContent = new Dictionary<int, string>();//key为要插入的index,value为插入的内容,也就是/r/n, /r/n/t, /r/n/t/t.../t StringBuilder tempBuilder = new StringBuilder(); foreach (HtmlNode htmlNode in lineCollection) { insContent.Add(htmlNode.StreamPosition, "\r\n"); if (htmlNode.HasChildNodes) { insContent.Add(htmlNode.FirstChild.StreamPosition, "\r\n\t"); insContent.Add(htmlNode.LastChild.StreamPosition + htmlNode.LastChild.OuterHtml.Length, "\r\n"); } foreach (HtmlNode hNode in htmlNode.Descendants())//遍历所有子代节点 { if (hNode.ParentNode.Name.Eq("style"))//此处的判断是针对HTMLAgility的一个Bug,当节点为<style>时,此节点的StreamPosition为0,这是不对的,正确值应为对应 的html字符串形式时的Index值 { continue; } if (hNode.PreviousSibling != null)//上一个兄弟节点 { if (!insContent.ContainsKey(hNode.StreamPosition)) { tempBuilder.Remove(0, tempBuilder.Length); tempBuilder.Append("\r\n"); for (int i = 0; i < parentNumbers(hNode, 1); i++) { tempBuilder.Append("\t"); } insContent.Add(hNode.StreamPosition, tempBuilder.ToString()); } } if (hNode.NextSibling != null)//下一个兄弟节点 { if (!insContent.ContainsKey(hNode.StreamPosition)) { tempBuilder.Remove(0, tempBuilder.Length); tempBuilder.Append("\r\n"); for (int i = 0; i < parentNumbers(hNode, 1); i++) { tempBuilder.Append("\t"); } insContent.Add(hNode.NextSibling.StreamPosition, tempBuilder.ToString()); } } if (hNode.HasChildNodes) { if (hNode.FirstChild != null)//第一个子节点 { if (!insContent.ContainsKey(hNode.FirstChild.StreamPosition)) { tempBuilder.Remove(0, tempBuilder.Length); tempBuilder.Append("\r\n"); for (int i = 0; i < parentNumbers(hNode.FirstChild, 1); i++) { tempBuilder.Append("\t"); } insContent.Add(hNode.FirstChild.StreamPosition, tempBuilder.ToString()); } } if (hNode.LastChild != null)//最后一个子节点 { if (!insContent.ContainsKey(hNode.LastChild.StreamPosition + hNode.LastChild.OuterHtml.Length)) { tempBuilder.Remove(0, tempBuilder.Length); tempBuilder.Append("\r\n"); for (int i = 0; i < parentNumbers(hNode, 1); i++) { tempBuilder.Append("\t"); } insContent.Add(hNode.LastChild.StreamPosition + hNode.LastChild.OuterHtml.Length, tempBuilder.ToString()); } } } } } foreach (KeyValuePair<int, string> item in insContent.OrderByDescending(n => n.Key))//倒序插入,保证原html不变 { content.Insert(item.Key, item.Value); } File.WriteAllText(filePath, content.ToString(), Encoding.UTF8); }好了,以上方法能够实现格式化一篇html的功能了,经测试,新浪,搜狐,网易的门户网站的html已经格式化成功,其实作者也可以看看这些门户网站的html代码,那是多么的乱。针对于HTMLAgility的类库和方法介绍的并不算全面,但是以上这些获取节点集合,属性集合,innerHtml等等吧,还有HtmlWeb类都是最常用的,解析HTML我想足够了,就这些吧。
相关文章推荐
- 经验总结21--抓取WEB数据,汇率,HtmlAgilityPack
- HtmlAgilityPack 总结(一)
- 经验总结21--抓取WEB数据,汇率,HtmlAgilityPack
- 总结一下HtmlAgilityPack
- htmlAgilitypack抓取页面总结
- 经验总结22--抓取HTML数据,HtmlAgilityPack(续)
- 经验总结22--抓取HTML数据,HtmlAgilityPack(续)
- HtmlAgilityPack 总结(一)
- HtmlAgilityPack 总结(一)
- HtmlAgilityPack下载开启压缩的页面乱码
- 通过HtmlAgilityPack实现网页信息抓取
- C# HTML解析 HtmlAgilityPack
- c#中的jQuery——HtmlAgilityPack
- [置顶]C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子)
- 利用 HtmlAgilityPack 抓取网页
- HtmlAgilityPack 分析Html代码
- .Net解析html文档类库HtmlAgilityPack完整使用说明
- Html Agility Pack解析HTML页
- c#蜘蛛程序之HTML解析利器HtmlAgilityPack