使用HtmlParser编写的抽取程序的缺点:
1.用Htmlparser写的程序很难去维护。
2.能否将要抽取的信息的定义和htmlparser程序分离?
3.用简单的办法解决问题。
抽取规则XML文件的编写规范
一.基础
Html文档由一系列的标签节点组成,这些节点使用树形结构组织,每一个标签节点由TagName,Attributes,以及ChildTags组成,我们要抽取一个信息总是要先对应到一个具体的标签节点上,然后再对这个标签节点进行操作从而获取要的信息,所要的信息可能是这个标签的某个属性,或者这个标签在界面上输出的字符串(忽略格式),或者是这个标签的Html等等,因此在抽取之前首先要定位到信息所在标签,我们称这个标签为元标签。
定位元标签的办法有:
- 直接通过这个元标签的标签名称,以及它的一些属性来定位。
例1:假如元标签是<div class=”thert”>...</div>那么我们可以通过两个限制条件来找到这个标签,分别是tagName=div,HasAttribute(class, thert).
- 如果我们要唯一的定位到某一个元标签,然而整个html文档却有多个满足类似办法1的限制条件的标签,这个时候可以尝试使用更加多的限制条件来定位到元标签,但仍然可能会失败。
例2:<div att1=value1>
<h1 att=v></h1>
</div>
<div att1=value2>
<h1 att=v ></h1>
</div>
如果我们使用tagName =h1,HasAttribute(att,v)来定位总是会定位到两个标签,然而如果我们能够考虑到一些层级信息,即如果我们先定位到<div att1=value1>,然后再以对应的html元标签作为html数据,再在里面定位<h1 att=v>就能够定位到<h1 att=v></h1>。
二.Auto_Parser
Xml文档的编写首先要符合XML文档的规范,有一个根节点,然后具体元标签的定位部分是在根节点内。
(1)有以下几种定位方式:
1.直接定位
如果我们要的元标签包含这样的结构<h1 class="articleTitle">,即标签名称是h1,包含一个属性值对class和articleTitle(也可能还有其他属性值对,但在class就已经可以准确定位的情况下其他属性值对就没必要列出来),那么我们可以这样定位
<h1 class="articleTitle"></h1>
2.带正则表达式的直接定位
<h1 class="\d+ " regex=”class”></h1>
其中regex属性不作为定位属性,其是用来声明元标签的class属性的值要满足正则表达式”\d+”.
<h1 att1=v1 att2=v2 class="\d+ "att3 = v3 att4=”[0-9 ]+ ” att5=v5 regex=”class; att3”></h1>
其中使用正则表达式的多个属性间使用”;”隔开,没有在regex中声明的属性不使用正则表达式方式。使用和不使用正则表达式的属性之间没有顺序要求,使用正则表达式的属性在regex中的声明也没有顺序要求。
- 使用层级关系的定位
每一级定位定位到一个或多个标签,然后下一级的定位是在上一级定位到的html标签中进行定位。每一级定位都是一次(带正则表达式的)直接定位,唯一的区别是下一级的定位是在上一级定位到的html标签中进行而不是在整个html文档中。
- 处在同一层上的定位
例2中<div att1=value1>和<div att1=value2>就是处在同一级上的定位,其含义是在它们共同上一级定位到的标签内,分别定位满足<div att1=value1>和<div att1=value2>的元标签,也就是它们的作用域是相同的。
5. 利用上下级标签的父子关系定位。
<div>
<a HasParent=”true”>
</a>
</div>
上述的HasParent属性并不作为真实的标签属性,其用来说明a标签的父亲标签是div,这样定位到的a标签只会是div的孩子,而不是除孩子以外的后代a标签结点。
6. 使用Order属性进行定位。
<table summary="World: Administrative Divisions">
<tr>
<td Order="2">
<a>
<extraction key="cap">
<text columnName="a"></text>
</extraction>
</a>
</td>
<td Order="8">
<a>
<extraction key="cap">
<attribute columnName="link">href</attribute>
<text columnName="name"></text>
</extraction>
</a>
</td>
</tr>
</table>
Order不作为真实的标签属性,其用来说明在找到的多个满足td的标签中的第二个(从1计)。
(2)定义要抽取的信息
1.在每一层的定位节点下都可以定义要抽取的信息,其作用域是该定位节点定位到的那些Html元标签。
2.定义的方式如
<p id="publishedOnlineDate">
<extraction key="cap">
<attribute columnName=”htmlID”>id</attribute>
<text columnName="pubDate" regex="\d+.*"></text>
<html columnName="pubDateHtml"></html>
</extraction>
</p>
*: 其中<extraction key="cap">是用来说明其内的信息是用来定义抽取内容的,每个定位标签下可以有0或者1个<extraction>,<extraction>不可以嵌套,一个定位层次中最内层必须要有<extraction>,最内层的祖先层可以有或无<extraction>。
Key用来表示抽取的信息所属的类别。
*: attribute是用来说明要抽取的是定位标签定位到的html元标签的某个属性信息,该属性的名称为id,该数据将被添加到由columnName标记的Vector<String>的尾部,也可以使用正则表达式对该属性值进行处理,和正则表达式匹配的数据部分将被存入,而不是整个数据,正则表达式的定义由regex属性说明。
*: text要抽取的是定位标签定位到的html元标签的toPlainTextString.就是该元标签输出到页面上字符串(忽略格式),其他和attribute相同,但是<text></text>之间没有内容。
*: html要抽取的是定位标签定位到的html元标签的html, 其他和text相同。
*: extraction中至少有attribute, text,html的一个,但不能是0个,可以多个attribute,多个text,多个html。
*: attribute标签中id部分可以是定位标签中没有的,但是必须是定位到的html元标签有的。
*: attribute, text,html都必须有columnName属性。
(3)抽取出来的信息的存放方式
HashMap<String,HashMap<String, Vector<String>>>
外层的key对应extraction中的key。
内层的Key对应于columnName的值,所有抽取下来的信息按照被抽取到的先后顺序存放在Vector<String>中,但是并不是在xml描述文档中的所有columnName都会在HashMap中,如果没有和columnName对应的数据被抽取下来,那么该columnName不会出现在HashMap中。