【转】 HtmlAgilityPack使用——XPath注意事项
【转】 HtmlAgilityPack使用——XPath注意事项
在使用HtmlAgilityPack这个开源的类库进行网页内容解析的时候是非常的方便(使用方法见另一篇博客《HTML解析:基于XPath的C#类库HtmlAgiliytyPack》),其基于XPath路径语法进行高效的选择文档节点,当发起请求获取了网页html文件的时候,解析的大部分工作量就落到了XPath路径表达式的书写了。本文测试在VS2010开发环境,.NetFramework
4.0 C#语言,使用的html如下:
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>test</title>
</head>
<body>
<div id="content">
<div>
<a href="http://www.google.com">google</a>
<div>gmail</div>
<div>google earth</div>
</div>
<div>
<a href="http://www.baidu.com">baidu</a>
</div>
<div>
<a href="http://www.tmall.com">tmall</a>
</div>
</div>
</body>
</html>
1、HtmlAgilityPack节点类型
在使用XPath表达式选择文档特定节点的时候,我发现有时候按照上下文写出的路径表达式就是失效,或者选择出错到了错误的内容,或者由于SelectSingleNode或者SelectNodes这个两个函数使用相应的XPath表达式查询的时候找不到结果而跑出异常。后来发现,HtmlAgilityPack对节点的选择严格按照XPath的规范来实现,XPath规范中严格定义了七种类型的节点(http://www.w3school.com.cn/xpath/xpath_nodes.asp):元素(Element),属性(Attribute),文本(Test),命名空间,处理指令,注释,文档根节点。基本值是无父或无子的节点,项目(Item)是基本值或者节点,然后又父子、同胞、先辈和后辈这些关系。HtmlAgilityPack的每个HtmlNode对象就封装好了上述所有规范定义的项目,下图是一个节点对象包含的内容。
正是因为如此,在书写XPath路径表达式的时候需要考虑到HtmlAgilityPack将text也作为了一个node,因此对于我们一般意义上看到的html结构就要多考虑一次text节点,空的文本节点也算再内,这在javascript的IE下的一个特例就是如此,为此需要特别为IE浏览器而书写兼容的js代码。使用如下的C#代码输出的是空字符串,也就是空的text节点。
HtmlDocument doc = new HtmlDocument();
doc.Load(@"C:\test.html");
HtmlNode main = doc.GetElementbyId("content");
HtmlNode child = main.FirstChild;
Console.WriteLine(child.InnerText);
以上结果输出为空:
这也就验证了,选取的为id为content的div节点的FirstChild节点是空的文本节点。因此对于FirstChild、LastChild、NextSibling、PrevSibling等关系表示的节点需要慎用,需要考虑空的text节点。
2、深刻理解“//”和“./”
XPath路径表达式中最关键的选择如下
| 表达式 | 描述 |
|---|---|
| nodename | 选取此节点的所有子节点。 |
| / | 从根节点选取。 |
| // | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
| . | 选取当前节点。 |
| .. | 选取当前节点的父节点。 |
| @ | 选取属性。 |
这也是书写路径表达式的基础,其中对于选择了一个节点之后,使用“//”和“./”这个两个语法总是会让人迷惑。本文实际测试了两者的区别。
- “//”:从当前选择的节点开始寻找,对于后面的表达式是在当前节点中的任意位置寻找,只要符合的就加入到选择结果中。
- “./”:也是从当前选择的节点开始选择,但是仅仅是寻找当前节点的直系子元素,而对于孙子及以后的节点都不考虑。
HtmlDocument doc = new HtmlDocument();
doc.Load(@"C:\test.html");
HtmlNode main = doc.GetElementbyId("content");
HtmlNodeCollection nodes = main.SelectNodes("./div");
foreach (HtmlNode node in nodes)
{
Console.WriteLine("=============start=============");
Console.WriteLine(node.InnerText);
Console.WriteLine("=============end===============");
}
上面输入结果如下:
使用如下代码继续测试:
HtmlDocument doc = new HtmlDocument();
doc.Load(@"C:\test.html");
HtmlNode main = doc.GetElementbyId("content");
HtmlNodeCollection nodes = main.SelectNodes("//div");
foreach (HtmlNode node in nodes)
{
Console.WriteLine("=============start=============");
Console.WriteLine(node.InnerText);
Console.WriteLine("=============end===============");
}
通过以上测试可以看出,根据路径表达式进行选择的时候需要进行特别区分出上述两者的区别,这样才能兼顾取得的结果是准确无误的。
HtmlDocument doc = new HtmlDocument();
doc.Load(@"C:\test.html");
HtmlNode main = doc.GetElementbyId("content");
HtmlNode node1 = main.SelectSingleNode("//div[1]/div[2]");
HtmlNode node2 = main.SelectSingleNode("./div[1]/div[2]");
Console.WriteLine(node1.InnerText);
Console.WriteLine(node2.InnerText);
上述结果可以看出根据路径表达式选择的时候结果可能是一样的,因此需要依据具体情况对待。
以上是本人使用HtmlAgilityPack解析html过程中书写XPath表达式得出的一些认识,希望供有用过的朋友可以一起探讨交流。
【转】 HtmlAgilityPack使用——XPath注意事项的更多相关文章
- C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子)
第一次接触HtmlAgilityPack是在5年前,一些意外,让我从技术部门临时调到销售部门,负责建立一些流程和寻找潜在客户,最后在阿里巴巴找到了很多客户信息,非常全面,刚开始是手动复制到Excel, ...
- 网页采集(通过HtmlAgilityPack+XPath)
有HtmlAgilityPack这个类库可以更方便地对HTML内容进行分析和提取.因此今天特别学习和实践了一下HtmlAgilityPack和XPath,并作下笔记. 1.下载HtmlAgilityP ...
- HtmlAgilityPack解析器在WP8.1下报错,不仅如此,社交化分享也报错。
以前WP7下是用的HtmlAgilityPack和 XPath来解析网页,很好用. 但是在Wp8.1下,这个里面却缺少了一个很重要的方法. HtmlDocument doc = new HtmlDoc ...
- C#+HtmlAgilityPack—>糗事百科桌面版V2.0
最近在浏览以前自己上传的源码,发现在糗事百科桌面端源码评论区中,有人说现在程序不能用了.查看了一下源码运行情况,发现是正则表达式解析问题.由于糗百的网页版链接和网页格式稍有变化,导致解释失败.虽然可以 ...
- C#+HtmlAgilityPack
C#+HtmlAgilityPack—糗事百科桌面版V2.0 最近在浏览以前自己上传的源码,发现在糗事百科桌面端源码评论区中,有人说现在程序不能用了.查看了一下源码运行情况,发现是正则表达式解析问 ...
- xpath语法分享
# xpath语法: ## 使用方式: 使用//获取整个页面当中的元素,然后写标签名,然后再写谓词进行提取.比如: ``` //div[@class='abc'] ``` ## 需要注意的知识点: 1 ...
- wIndows phone 7 解析Html数据
原文:wIndows phone 7 解析Html数据 在我的上一篇文章中我介绍了windows phone 7的gb2312解码, http://www.cnblogs.com/qingci/arc ...
- Html Agility Pack - API
Html Agility Pack - APIParserSelectorsManipulationTraversingWriterUtilitiesAttributes HTML Parser HT ...
- C# 获取QQ群数据的实现
一,分析 1,群数据获取 当访问http://qun.qq.com/air/#mygroup我们通过Fiddler可以查看到QQ群列表是从http://qun.qq.com/air/group/min ...
随机推荐
- SpringCloud学习笔记(13)----Spring Cloud Netflix之Hystrix断路器的隔离策略
说明 : 1.Hystrix通过舱壁模式来隔离限制依赖的并发量和阻塞扩散 2. Hystrix提供了两种隔离策略:线程池(THREAD)和信号量隔离SEMAPHORE). 1. 线程池隔离(默认策略模 ...
- SpringBoot学习笔记(10)-----SpringBoot中使用Redis/Mongodb和缓存Ehcache缓存和redis缓存
1. 使用Redis 在使用redis之前,首先要保证安装或有redis的服务器,接下就是引入redis依赖. pom.xml文件如下 <dependency> <groupId&g ...
- SAI / PS绘画一个卡通女孩详解
本教程介绍使用SAI / PS绘画一个卡通女孩的教程 ,教程很详细,动起你的小手一起来试试吧! 软件下载:http://www.dongmansoft.com/xiazai.html 想要Get到更多 ...
- 联想lenovo 家用电脑安装win7 无法引导问题(新电脑安装系统时提示File:\Boot\BCD错误解决方案)
安装方式 : 1.进入 PE 2.用 EasyimageX 恢复 GHO镜像 3.重启后出现 原因: 主要 是安装win7 时,格式 化选择为GUID模式. 处理: win7 以后,格式华时选择MB ...
- [国家集训队]最长双回文串 (PAM)回文自动机
Code: // luogu-judger-enable-o2 #include <cstdio> #include <algorithm> #include <cstr ...
- 数组的常用方法 Array;
数组: 1,arr.join();//返回默认由逗号隔开的一个字符串,传参则返回所传参数隔开的一个字符串; 2,arr.push();//往数组最后添加数据,返回新的数组的length,这个方法将改变 ...
- WebLogic 服务器配置
环境版本 Windows 8.1 WebLogic 10.3.0 JDK:1.6 WebLogic 创建域在Windows环境下有两种方式: 1.直接在开始菜单创建domai ...
- 【BZOJ 1196】[HNOI2006]公路修建问题
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 二分最后选的边中的最大值是多少. mid 则所有边权小于等于mid的边都可以用了. 那么我们要怎么选择呢? ->优先选择一级的 ...
- Mysql学习总结(26)——MySQL子查询
mysql中虽然有连接查询实现多表连接查询,但是连接查询的性能很差,因此便出现了子查询. 1.理论上,子查询可以出现在查询语句的任何位置,但实际应用中多出现在from后和where后.出现在from后 ...
- C# winform压缩文件夹带进度条
注意:用了开源的CL.IO.Zip库 pbYSJD是进度条的控件名 btnImport是按钮控件名,当压缩结束之后,使按钮处于激活状态,否则无法点击按钮. /// <summary> // ...