静态页面采集工具(只需要编写XML文件即可以完成采集配置)

之前在实验室做了很多静态页面数据采集的工作,需求是这样的,一个静态页面,需要将页面中的若干元素采集下来保存成键值对,刚开始是使用HtmlParser做的,后来发现使用HtmlParser编写的采集规则很繁琐,并且一旦有需求变更,很难去维护,于是产生了做一个通过外部XML配置就可以做采集的通用的工具包,下面是我之前写的一些设计思想以及抽取规则XML文件的编写规范,还有些不够完善,以后有时间在改一改,最近有点忙。

工具包的SVN:http://web-auto-parser.googlecode.com/svn/trunk/

 

抽取规则XML文件的编写规范

一.基础

Html文档由一系列的标签节点组成,这些节点使用树形结构组织,每一个标签节点由TagName,Attributes,以及ChildTags组成,我们要抽取一个信息总是要先对应到一个具体的标签节点上,然后再对这个标签节点进行操作从而获取要的信息,所要的信息可能是这个标签的某个属性,或者这个标签在界面上输出的字符串(忽略格式),或者是这个标签的Html等等,因此在抽取之前首先要定位到信息所在标签,我们称这个标签为元标签。

定位元标签的办法有:

1. 直接通过这个元标签的标签名称,以及它的一些属性来定位。

例1:假如元标签是<div class=”thert”>...</div>那么我们可以通过两个限制条件来找到这个标签,分别是tagName=div,HasAttribute(class, thert).

2. 如果我们要唯一的定位到某一个元标签,然而整个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>。

二.ZParser

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中的声明也没有顺序要求。

3. 使用层级关系的定位

每一级定位定位到一个或多个标签,然后下一级的定位是在上一级定位到的html标签中进行定位。每一级定位都是一次(带正则表达式的)直接定位,唯一的区别是下一级的定位是在上一级定位到的html标签中进行而不是在整个html文档中。

4. 处在同一层上的定位

例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中。

posted on 2012-09-05 23:03  Razzit  阅读(1177)  评论(0编辑  收藏  举报

导航