《搜索引擎零距离》第二章 IRS(5)

roki 2009-06-18
3.2.21  IRQL语言中的数据表
IRQL语言中有3种不同类型的表结构,把爬虫遍历目标页面过程中能够收集到的各种数据以不同的存储形式在IRQL中分为3类:共享表、独立表、继承表。
1.共享表
首先,共享表属于某个页面,这个页面上所有的“模式匹配结果数据集”都会存储在这个页面上的共享表里。比如这样一个层次的网站:分类列表页->小说列表页->详细信息页。
爬虫首先访问如下内容的页面:

Some HTML
<td><a href=” category.jsp?cate=1>武侠<a></td>
<td><a href=” category.jsp?cate=2>都市<a></td>
Some HTML
<li><a href=” category.jsp?cate=3>玄幻<a></li>
<li><a href=” category.jsp?cate=4>言情<a></li>
Some HTML


我们发现,需要采集的数据有两种模式,因此需要写两种“模式匹配语句”。因此编写如下IRS语句:
------------------------
页面配置
	页面名 '分类列表页'
	匹配:'category1' '<td><a href="category.jsp?cate=[$]>[$cateName]</a></td>' ' %enter1'
	匹配:'category2'<li><a href="category.jsp?cate=[$]>[$cateName]</a></li>' ' %enter2'
	次级 页内 '%enter1' '列表页'
	次级 页内 '%enter2' '列表页'
	…
;
---------------------------


上述IRS代码将使用category1和category2两个模式去匹配出完整的结构化数据,两组不同的模式匹配出的数据将被存放在属于页面“分类列表页”的共享表里。“分类列表页”的ShareTable中的内容如下:

ShareTable:“分类列表页”=>
cateName
武侠
都市
玄幻
言情
2.独立表
独立表的主要特点是,把从不同的模式里提取的数据放入不同的表里去。对于上节中的例子,独立表里的数据表现如下:

UniTable:  category1=>
cateName
武侠
都市

UniTable:category2=>

cateName
玄幻
言情

3.继承表
继承表的产生需要一个前提条件,就是爬虫从“分类列表页”得到“小说列表页”的URL后,进入这个URL地址之后,继承表上就会加入“分类列表页”上入口地址上的数据,进一步进入“详细信息页”之后,继承表上又会加入“小说列表页”上的入口地址上的数据,以下用例子具体说明。
爬虫从“分类列表页”的“武侠”条目进入“小说列表页”,这个时候,继承表的内容如下:

HierTable: {“分类列表页”=>{cateName=>武侠}}

假设“小说列表页”内容如下:

1.一片空白(孙喜平)
2.爱,在你转身时盛开(千寻千寻)
3.武警机动队(黄明军)
4.秘密列车(张宝瑞)

爬虫从第一个条目进入“详细信息页”,进入这个下级页面之后,继承表的内容如下:

HierTable: {
"分类列表页"=>{cateName=>武侠},
"小说列表页"=>{bookName=>"一片空白",authoer="孙喜平"}
}

另外,当爬虫进入“详细信息页”之后,就可以在对页面内容进行设置中使用以下模式匹配语句

-------------------------------------
页面名 '详细信息页'
匹配:'book' ' ([$]评)([status])[$]简介:[$brief]…'
;
----------------------------------


来获得如表3.11所示的一个独立表。
表3.11  UniTable:“详细信息页”->book

status brief
连载中 商都市中级法院刑事审判庭庭长萧亚东…


以及一个内容与独立表相同的共享表ShareTable:“详细信息页”内容如下:

一片空白(0评)(连载中)

简介:商都市中级法院刑事审判庭庭长萧亚东和公安局刑侦支队长舒琳,是一对工作狂夫妻。其宝贝女儿璐璐不得不因为父母的无暇顾及而常常到楼下邻居杜爷爷家“混”饭吃。

4.结果数据集表示方法
在上节中的例子上,我们已经从遍历的三个页面中获得了一系列信息,但这些信息是零散的,需要整理成完整的结构化数据,IRQL语句正可以起到这样的作用。
在上述的例子中,我们实际希望得到的是一个小说的完整信息,如表3.12所示。
表3.12  小说完整信息
bookName category author status brief
一片空白 武侠 孙喜平 连载中 商都市中级法院刑事审判庭庭长…


其中,category字段的值“武侠”在“分类列表页上”,bookName字段的值“一片空白”和author字段的值“孙喜平”在“小说列表页上”,status字段的值“连载中”和brief字段的值“商都市中级法院刑事审判庭庭长…”在“详细信息页”上。
对于这样一种情况,我们可以用以下的策略得到需要的数据:
首先,从

HierTable:{
"分类列表页"=>{category=>"武侠"},
"小说列表页"=>{bookName="一片空白",author=>"孙喜平"}
}

这个继承表中获得category, bookName, author这3个字段的值对应的IRQL语言片段是

--------------------------
分类列表页:P1, 小说列表页:P2; select P1->category, P2-> bookName, P2-> author
--------------------------


上述片段中,分号前的是“页面别名声明”,分号后的是“字段选择语句”,其中页面别名P1和字段名category之间的箭头(->)表明这个字段的值要从继承表去取,并且是“继承表”上P1所代表的“分类列表页”上的数据中的category字段的值。最后,从ShareTable:“详细信息页”(如表3.13所示) 中取出status和brief两个字段的值。
表3.13  ShareTable“详细信息页”
状  态 简  介
连载中 商都市中级法院刑事审判庭庭长萧亚东…


事实上,完整包含所有字段的一条小说数据是由3个数据表作“表连接操作”而形成的,这里的“表连接操作”与SQL语言中同名的术语是相同的含义。

武侠
X
一片空白 孙喜平
X
连载中 商都市中级法院刑事审判庭庭长萧亚东…
=
武侠 一片空白 孙喜平 连载中 商都市中级法院刑事审判庭庭长萧亚东…

上述的公式表达了3个数据表作“表连接”操作之后形成一张新数据表的过程。这个操作用IRQL语言来表达就是:

--------------------------
分类列表页:P1, 
小说列表页:P2
详细信息页:P3;
select P1->category, P2-> bookName, P2-> author,P3.status,P3.brief;
--------------------------


按照上述的一系列业务逻辑,爬虫就可以从“页面列表”页找到所有16个“分类列表页”,然后从每个“分类列表页”上找到每个“小说详细页”的地址,最后获得每个小说完整的信息。假设总共16个分类,每个分类里有1000本书的话,就可以获得16 000条形式类似的数据,这些数据可以转化成SQL语言直接插入外部关系型数据库。

武侠 一片空白 孙喜平 连载中 商都市中级法院刑事审判庭庭长萧亚东…


首先,如果我们对数据有一些过滤的要求,比如,作者为“匿名”或者为空的不要,可以在select子句后加上where子句来实现条件过滤,上述的过滤需求就可以表达为where author !=“匿名 and author IS NOT NULL”;其次,如果我们需要限制简介字段的长度,比如最大2000字,则可以在brief字段上使用IRS内部支持的maxlength函数;最后,如果我们希望在最终结果上加一个固定字段,比如记录数据来源,站点名“新浪读书频道”,则可以在IRQL中这样写:

novelDao->insert("srcSite"=>"新浪读书频道")

加上这句之后,最终准备插入数据库的数据就是如表3.14所示的形式。
表3.14  插入数据库的数据
category bookname author status brief srcSite
都市 一片空白 孙喜平 连载中 商都市… 新浪读书频道
武侠 搜神记 树下野狐 连载中 神话、魔幻… 新浪读书频道
… … … … … …


综合以上数据处理要求,完整的IRQL语句如下:

--------------------------
'NULL;
分类列表页:P1, 
小说列表页:P2,
详细信息页:P3;
select P1->category, P2-> bookName, P2-> author,P3.status, maxlengh(P3.brief,"2000") brief
where author !="匿名 and author IS NOT NULL ;
novelDao->insert("srcSite"=>"新浪读书频道")'
--------------------------

Global site tag (gtag.js) - Google Analytics