【转】 HTML解析:基于XPath的C#类库HtmlAgiliytyPack
【转】 HTML解析:基于XPath的C#类库HtmlAgiliytyPack
最近处于毕业设计开始阶段,前期工作需要去国外的一些专业数据库网站比对一些所需TF家族信息,为了快捷方便,想到用程序去帮助实现。前期实现了一系列的尝试,使用C#的的网络编程类库,获取查询结果,但是为了分析其中的结果并进行比对,我最开始尝试了两天之久的正则表达式,最后发现在解析这样的HTML文档的时候,花费时间太多,因此开始改变策略,最后得知MSHTML和HAP这两个.NET解析html的类库,出于对HAP这个轻量级类库兴趣,决定使用它来解析获取信息。
一、HAP简介
HAP是codeplex公司的一个解析html的.NET开源项目,支持XPath查询。官网(http://htmlagilitypack.codeplex.com/)给出的介绍是:
What is exactly the Html Agility Pack (HAP)?
This is an agile HTML parser that builds a read/write DOM and supports plain XPATH or XSLT (you actually don't HAVE to understand XPATH nor XSLT to use it, don't worry...). It is a .NET code library that allows you to parse "out of the web" HTML files. The
parser is very tolerant with "real world" malformed HTML. The object model is very similar to what proposes System.Xml, but for HTML documents (or streams).
目前最新版本为HAP1.4.6,推出的新特性是支持Linq语言。
二、XPath
为了更好的使用HAP,必须了解XPath语言。维基百科介绍如下:
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。
XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。起初XPath的提出的初衷是将其作为一个通用的、介于XPointer与XSL间的语法模型。但是XPath很快的被开发者采用来当作小型查询语言。
XPath中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释、根节点。节点关系有:Parent、Children、Sibling、Ancestor、Descendent。
路径表达式用来选取节点或节点集,通过路径(path)或步(steps)进行选取。
节点表达式:
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点。 |
/ | 从根节点选取。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. | 选取当前节点。 |
.. | 选取当前节点的父节点。 |
@ | 选取属性。 |
路径表达式 | 结果 |
---|---|
bookstore | 选取 bookstore 元素的所有子节点。 |
/bookstore |
选取根元素 bookstore。 注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径! |
bookstore/book | 选取属于 bookstore 的子元素的所有 book 元素。 |
//book | 选取所有 book 子元素,而不管它们在文档中的位置。 |
bookstore//book | 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。 |
//@lang | 选取名为 lang 的所有属性 |
谓语:用来查找某个特定的节点或者包含某个指定的值的节点。谓语被嵌在方括号中
路径表达式 | 结果 |
---|---|
/bookstore/book[1] | 选取属于 bookstore 子元素的第一个 book 元素。 |
/bookstore/book[last()] | 选取属于 bookstore 子元素的最后一个 book 元素。 |
/bookstore/book[last()-1] | 选取属于 bookstore 子元素的倒数第二个 book 元素。 |
/bookstore/book[position()<3] | 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。 |
//title[@lang] | 选取所有拥有名为 lang 的属性的 title 元素。 |
//title[@lang='eng'] | 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。 |
/bookstore/book[price>35.00] | 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。 |
/bookstore/book[price>35.00]/title | 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。 |
通配符:
通配符 | 描述 |
---|---|
* | 匹配任何元素节点。 |
@* | 匹配任何属性节点。 |
node() | 匹配任何类型的节点。 |
选取多个路径时,使用 “ | ”符号。
步(Step):语法为 轴名称::节点测试[谓语]
轴(axis)-------------------------------定义所选节点与当前节点之间的树关系
节点测试(node-test)----------------识别某个轴内部的节点
零个或多个谓语(predicate)--------更深入提炼所选的节点集
XPath轴:
轴名称 | 结果 |
---|---|
ancestor | 选取当前节点的所有先辈(父、祖父等)。 |
ancestor-or-self | 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。 |
attribute | 选取当前节点的所有属性。 |
child | 选取当前节点的所有子元素。 |
descendant | 选取当前节点的所有后代元素(子、孙等)。 |
descendant-or-self | 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。 |
following | 选取文档中当前节点的结束标签之后的所有节点。 |
namespace | 选取当前节点的所有命名空间节点。 |
parent | 选取当前节点的父节点。 |
preceding | 选取文档中当前节点的开始标签之前的所有节点。 |
preceding-sibling | 选取当前节点之前的所有同级节点。 |
self | 选取当前节点。 |
XPath可以使用运算符:
运算符 | 描述 | 实例 | 返回值 |
---|---|---|---|
| | 计算两个节点集 | //book | //cd | 返回所有拥有 book 和 cd 元素的节点集 |
+ | 加法 | 6 + 4 | 10 |
- | 减法 | 6 - 4 | 2 |
* | 乘法 | 6 * 4 | 24 |
div | 除法 | 8 div 4 | 2 |
= | 等于 | price=9.80 |
如果 price 是 9.80,则返回 true。 如果 price 是 9.90,则返回 false。 |
!= | 不等于 | price!=9.80 |
如果 price 是 9.90,则返回 true。 如果 price 是 9.80,则返回 false。 |
< | 小于 | price<9.80 |
如果 price 是 9.00,则返回 true。 如果 price 是 9.90,则返回 false。 |
<= | 小于或等于 | price<=9.80 |
如果 price 是 9.00,则返回 true。 如果 price 是 9.90,则返回 false。 |
> | 大于 | price>9.80 |
如果 price 是 9.90,则返回 true。 如果 price 是 9.80,则返回 false。 |
>= | 大于或等于 | price>=9.80 |
如果 price 是 9.90,则返回 true。 如果 price 是 9.70,则返回 false。 |
or | 或 | price=9.80 or price=9.70 |
如果 price 是 9.80,则返回 true。 如果 price 是 9.50,则返回 false。 |
and | 与 | price>9.00 and price<9.90 |
如果 price 是 9.80,则返回 true。 如果 price 是 8.50,则返回 false。 |
mod | 计算除法的余数 | 5 mod 2 | 1 |
XPath有一百多个函数,常用在谓语中选择的函数有
position() 表示当前节点的序号
last() 表示取最后一个节点
name() 表示当前节点名字
在.NET中可以使用XPath处理XML文档,此处的html解析就是运用XPath查询选择。
三、HAP使用
1、下载HtmlAgilityPack最新压缩包,http://htmlagilitypack.codeplex.com/releases/view/90925,官方下载地址。
2、加压后,在所需项目中添加引用HtmlAgilityPack.dll文件,其中还附带了xml文件用于文档说明。然后添加using HtmlAgilityPack说明。如下图所示:
3、实际使用中,都是以HtmlDocument类为主线。HAP提供了两种不同方式加载HtmlDocument类的实例:从html字符串构造(可以使用LoadHtml方法和Load方法),从html文档流构造实例(使用Load方法)。从而就可以实例化一个DOM实例,对于客户端脚本语言JavaScript熟悉的开发者来说这是非常熟悉的。这些操作也与.net framework中的XmlDocument类对于XML文档的操作非常类似,而且XML操作中也支持使用XPath表达式的查询使用,不同的是HtmlDocument强化了GetElementById方法,可以直接使用定位。示例代码如下:
- HtmlDocument hd = new HtmlDocument();
- hd.LoadHtml(fileStr);
- HtmlNode root = hd.DocumentNode;
- HtmlNodeCollection hNodes = root.SelectNodes("//tr[@class='odd']|//tr[@class='even']/td[@class='rowNum']");
4、后续的使用需要依照自己的实际需求来设计。对于html文档的解析主要就是使用XPath表达式进行选择定位,可以参考http://www.w3school.com.cn/xpath/xpath_syntax.asp。
5、去除script和style等标签。当使用document.DocumentNode.InnerText获取文档内容时会包含script等标签,因此可以使用下面的方法去除:
- foreach(var script in doc.DocumentNode.Descendants("script").ToArray())
- script.Remove();
- foreach(var style in doc.DocumentNode.Descendants("style").ToArray())
- style.Remove();
- foreach(var comment in doc.DocumentNode.SelectNodes("//comment()").toArray())
- comment.Remove();
6、在下载的HtmlAgilityPack压缩包中还找到了关于WindowsPhone开发需要的dll文件,因此对于开发WP手机应用也是非常的有效。
HtmlAgilityPack对于html页面的解析、信息采集的准确度和效率都优于使用正则表达式,而且对开发者非常友好,特别是正则表达式的学习曲线较陡,而且其中包含了很多的技巧,特别是对高效的正则表达式的书写是非常需要经验的。HtmlAgilityPack获取html文档时对原文本的结构要求是非常宽松的,这与XmlDocument的严格要求是不同的。基本上熟悉了XPath的语法之后,大部分应用都可以满足要求了。
参考资料:
1、HAP:简单好用的html解析器:http://msdn.microsoft.com/zh-tw/ee787055.aspx
2、XPath维基百科:http://zh.wikipedia.org/zh-cn/XPath
3、W3C school:http://www.w3school.com.cn/xpath/xpath_syntax.asp
4、C#:HtmlAgilityPack extract inner text:http://stackoverflow.com/questions/2785092/c-htmlagilitypack-extract-inner-text
【转】 HTML解析:基于XPath的C#类库HtmlAgiliytyPack的更多相关文章
- Python网络爬虫之三种数据解析方式 (xpath, 正则, bs4)
引入 回顾requests实现数据爬取的流程 指定url 基于requests模块发起请求 获取响应对象中的数据 进行持久化存储 其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指 ...
- 基于WinCE的JSON 类库 源码
基于WinCE的JSON 类库,可以将对象序列化成字符串和文件. 提示,其在反序列化时有一个BUG: 如果对象的某个字段值为 null,将其序列化成字符串,然后将该字符串反序列化成对象时会报异常. 这 ...
- String,StringBuffer和StringBuilder源码解析[基于JDK6]
最近指导几位新人,学习了一下String,StringBuffer和StringBuilder类,从反馈的结果来看,总体感觉学习的深度不够,没有读出东西.其实,JDK的源码是越读越有味的.下面总结一下 ...
- Csharp调用基于Opencv编写的类库文件
现在将Csharp调用基于Opencv编写的类库文件(Dll)的方法定下来,我取名叫做GreenOpenCsharpWarper,简称GOCW. 一.CLR编写的DLL部分 1.按照正常方法引入Ope ...
- 基于js-spark-md5前端js类库,快速获取文件Md5值
js-spark-md5是歪果仁开发的东西,有点多,但是我们只要一个js文件即可,具体类包我存在自己的oschina上,下载地址:https://git.oschina.net/jianqingwan ...
- 爬虫的两种解析方式 xpath和bs4
1.xpath解析 from lxml import etree 两种方式使用:将html文档变成一个对象,然后调用对象的方法去查找指定的节点 (1)本地文件 tree = etree.parse(文 ...
- 爬虫之解析库Xpath
简介 XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言. XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力.起初XPat ...
- 爬虫解析库xpath
# xpath简介 XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言.用于在 XML 文档中通过元素和属性进行导航. XPath基于XM ...
- 网页解析:Xpath 与 BeautifulSoup
1. Xpath 1.1 Xpath 简介 1.2 Xpath 使用案例 2. BeautifulSoup 2.1 BeautifulSoup 简介 2.2 BeautifulSoup 使用案例 1) ...
随机推荐
- 【参考】JDBC执行存储过程的四种情况
[1].只有输入IN参数,没有输出OUT参数 [2].既有输入IN参数,也有输出OUT参数,输出是简单值(非列表) [3].既有输入IN参数,也有输出OUT参数,输出是列表 [4].输入输出参数是同一 ...
- 一个渣渣python脚本,用wol控制开机
#!/usr/bin/env python #coding:utf8 import os,time d={} '''f = open('E:\info.txt','r') for ipmac in f ...
- C语言基础 (1) 操作系统介绍,linux入门
第一天 一.操作系统 1.1.1操作系统的目标 ·方便:使计算机系统易于使用 ·有效:以更有效的方式使用计算机系统资源 ·扩展:方便用户有效开发.测试和引进新功能 1.1.2 操作系统的地位 操作系统 ...
- 关于vue事件监听的一个问题
由于新工作需要用vue,所以最近接触最多的也是vue,因为之前一直在用react,所以对于vue上手还是很快的.我也尽量找一些他们两个的异同点,除了多了一些辅助用的方法以外,最大的不同应该是对于组件间 ...
- 虚拟机VM安装Linux系统CentOS7
第一步:安装一个VM虚拟机: 百度VM,使用普通下载,一路Next即可 如果需要输入序列号,可以网上随意找一个,目前是个人可以随意激活,但如果做商业用途的话,还是最好买一个序列号,我在网上搜到的:5A ...
- POJ——T1860 Currency Exchange
http://poj.org/problem?id=1860 Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 29874 ...
- 零基础学python-6.2 共享引用
这一章节说说共享引用 我们先举一个样例 a=1 b=a 上面的样例就是共享引用,这里我们说说整个过程: 1.创建一个对象1 2.创建一个变量a 3.把a和1所在的内存空间连接起来.就是a引用1 4.a ...
- iOS开发 - 二维码的生成与读取
二维码的生成 从iOS7開始集成了二维码的生成和读取功能 此前被广泛使用的zbarsdk眼下不支持64位处理器 生成二维码的步骤: 导入CoreImage框架 通过滤镜CIFilter生成二维码 二维 ...
- ftoa浮点型转换成字符串
#include <stdio.h> bool ftos(float num,char *s,int n) { int temp; float t=num; int pn=0; b ...
- HDU 3652 B-number(数位dp&记忆化搜索)
题目链接:[kuangbin带你飞]专题十五 数位DP G - B-number 题意 求1-n的范围里含有13且能被13整除的数字的个数. 思路 首先,了解这样一个式子:a%m == ((b%m)* ...