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

roki 2009-06-18
3.2.16  爬虫配置语句
爬虫配置语句是一个集中配置与爬虫相关的配置选项的语句,供3.2.3节中的“爬虫配置声明语句”来引用。
示例:

-------------------------------------------------------------------
爬虫配置: 名称=conf1,编码=UTF-8,最大线程数=3 ,抓取延迟=1000,输出=数据库 .
-------------------------------------------------------------------


上述配置中各个字段的意义说明如下。
 名称:本爬虫配置的命名,供“爬虫配置声明语句”引用。
 编码:默认的用来解析页面的编码。
 最大线程数:最多同时运行的爬虫任务数。
 抓取延迟:每次访问一个页面之后,爬虫的暂停时间。
 输出:执行保存语句之后的目标存储位置,默认是输出到控制台。
爬虫配置语句的格式是:

爬虫配置:key1=value1, …,keyN=valueN.

以“:开头”,“.结尾”,用“=”分隔键和值,用,分隔多个键值对。
3.2.17  系统配置语句
系统配置语句是针对IRS虚拟机的配置,比如爬虫发送HTTP请求时所使用的代理服务器地址。系统配置的文本内容是一个单引号包围的字符串。
示例:

-----------------------------------------------------------
系统配置 '代理服务器= myproxy.com:8080
		  otherKey=otherValue'
-----------------------------------------------------------


系统配置语句的格式是:

系统配置 '
key1=value1

keyN=valueN
'

以单引号开头和结尾,用“=”分隔键和值,用换行分隔多个键值对。

3.2.18  外部配置文件
对于某些比较复杂的配置,IRS脚本内部的简单配置格式就无法表达了,因此引入了外部配置文件的概念。
IRS的外部配置文件的一个示例如sampeConf.xml所示:
<?xml version="1.0" encoding="GBK"?>
<configuration>

	<!--某个站点同时并发请求数配置-->
	<maxSiteLink>
		<site domain="bookwap.net" link="2"/>
		<site domain="wap.uucun.com" link="4"/>
	</maxSiteLink>
	
	<!--代理列表配置-->
	<proxylist>
	</proxylist>
	
	<irs>
		<pages>
			<!--处理某个页面时,使用哪个http配置-->
			<page name="resumepage" http="listHttp"/>
			<page name="crawlerGui" http="otherHttp"/>
		</pages>
		
		<!--配置一个httphead,以供下面的http配置引用-->
		<head name="rootHead">
			<item key="Referer"	value="http://www.sc.sh.cn/ "/>
			<item key="User-Agent"	value="Mozilla/4.0"/>
			<item key="Cookie"	value="SESSIONI=KHOAB"/>
		</head>
		
	<!--配置一个http,以供page配置引用引用,
它的head属性引用上文中定义的head节点-->
		<http name="listHttp" method="POST" head="rootHead">
			<body>
	<![CDATA[sex=0&age_down=&age_up=&city=0&degree_id=0&d_way=0&computer_level=0&foreign1=0&foreign1_extent=0&function_big=11&function_small=&keyword=]]>
			</body>
			<Content-Type>application/x-www-form-urlencoded</Content-Type>
		</http>

	<!--配置一个另一个http,以供名为"CrawlGui"的page配置引用-->
		<http name="otherHttp" method="POST" head="rootHead">
			<body>
	<![CDATA[sex=0&age_down=&age_up=&city=0&degree_id=0&d_way=0&computer_level=0&foreign1=0&foreign1_extent=0&function_big=11&function_small=&keyword=]]>
			</body>
			<Content-Type>application/x-www-form-urlencoded</Content-Type>
		</http>
	</irs>
	
</configuration>

通过上面这个外部配置文件,我们可以更精确的定义智能爬虫的行为,从而可以满足各种HTTP访问方式的苛刻要求。为了使得某个IRS脚本能够使用这个配置文件,需要在脚本中加上一句:系统配置 '外部配置文件=sampleConf.xml'。

3.2.19  执行语句块
执行语句块里表述了爬虫如何读取页面配置来开始信息采集任务。
示例:

-------------------------------------------------
	执行
		抓取 页面名 '灯火书城'
	;
-------------------------------------------------


上述语句的意义是,执行名叫“灯火书城”的页面配置所定义的抓取任务。执行语句块的格式是:

执行
抓取 页面名 'page1'
抓取 页面名 'page2'
….
抓取 页面名 'pageN'
;

语句从“执行”开始, 以一个分号(;)结束。

3.2.20  IRQL存储语句
IRQL存储语句的设计目的是为了处理数据。为了把爬虫系统在遍历各种网页的过程中收集到的各种数据(树状的、层次的、复杂的结构化数据)整理、提取成适合通用的关系型数据库(比如Oracle)能够存储的格式,需要一种表达力比较强的数据描述语言,因此笔者仿造SQL设计了这种IRQL(Information Retrival Query Language)语言,并用一个Java语言编写的小型数据库引擎提供了对IRQL语言的支持。
一个IRQL语句由5部分组成:特殊处理语句、页面别名声明语句、字段选择语句、结果过滤条件和存储对象语句。
IRQL示例:

	'href->contentLink,更多小说页->小说入口.href->detailLink;
	17K手机入口页:P1,
	更多小说页:P2,
	更多.详细信息页:P3;
	select P1->cateName,P2->bookName,P2->author,P2-> detailLink,P3.status,P3.brief,P3.contentLink;
	novelDao->insert("srcSite"="风雨书城")'


上述IRQL由4段组成,由3个;分隔开。语法格式:

IRQL='特殊处理语句;页面别名声明语句;字段选择语句;存储对象语句'

1. 特殊处理语句
特殊处理语句的作用是对结果集做一些额外的处理,多个特殊处理语句之间用逗号分隔。

2. 多表融合语句
存在这样一种比较复杂的场景:某页面上,需要执行两种匹配,title和describe,因此需要写两个IEE表达式,比如:

-------------------------------------------------------
匹配:'title1'  '<title>[$title]<title>'
匹配:'describe1'  '描述:[$describe]<br/>'
-------------------------------------------------------


但是,由于目标页面有两种模板,也就是说,有时候title和describe需要用以下IEE获取:

-------------------------------------------------------
匹配:'title2'  '<H>[$title]</H>'
匹配:'describe2  '简介:[$describe]<br/>'
-------------------------------------------------------


综合以上情况,最后的IRS的主要语句片段的写法是:
-------------------------------------------------------
页面配置
页面名 '结果页'
匹配:'title1'  '<title>[$title]<title>'  'NULL'
匹配:'describe1'  '描述:[$describe]<br/>' 'NULL'
匹配:'title2'  '<H>[$title]</H>'  'NULL'
匹配:'describe2'  '简介:[$describe]<br/>'  'NULL'
保存:'savetb' '
merge(结果页->title1结果页-> describe1结果页->title2 结果页-> describe2)=>结果页->newtb;
结果页-> newtb:P;
select P.title,P.describe;
dao->insert();
'
Ruby: '
	#在IEE'title1'匹配失败的情况下,尝试'title2'
	if(!vm.match('title1'))
		vm.match('title2');
	end

	#在IEE'describe1'匹配失败的情况下,尝试'describe2'
	if(!vm.match('describe1))
		vm.match('describe2);
	end
	#执行保存语句'savetb'
	vm.save('savetb');
'
-------------------------------------------------------


以上IRS片段中关键的是这句:

merge(结果页->title1结果页-> describe1结果页->title2 结果页-> describe2)=>结果页->newtb;

这个特殊处理语句的功能是把4张表中匹配到的数据融合到一起,上述4个表的名称“结果页->title1  结果页-> describe1   结果页->title2 结果页-> describe2”用空格或换行符分开,=>符号后面跟上融合后的表的名称“结果页->newtb”,然后就可以在页面别名语句中用“结果页->newtb:P”来声明页面别名了,最后就可以使用字段选择语句select P.title,P.describe来获得如表3.4所示形式的数据。
表3.4  结果页->newtb
Title Describe
SampleTitle1 SampleDescribe1
SampleTitle2 SampleDescribe2


这个表实际上是以下4张表融合的结果,我们分析一下各种可能出现的情况。
情况1:在IEE title1和describe1匹配成功的情况下,4个表的内容如表3.5和表3.6所示。
表3.5  结果页->title1
Title Describe
SampleTitle1

表3.6  结果页->describe1
Title Describe
SampleDescribe


而结果页->title2和结果页->describe2都是空表,这4个表融合成第一条记录SampleTitle1,SampleDescribe1。
情况2:在IEEtitle2和describe2匹配成功的情况下,4个表的内容如表3.7和表3.8所示。
表3.7  结果页->title2
Title Describe
SampleTitle2

表3.8  结果页->describe2
Title Describe
SampleDescribe2


而结果页->title1和结果页->describe1都是空表,这4个表融合成第二条记录SampleTitle2,SampleDescribe2。同样,如果title1和describe2匹配成功,或者title2和describe1匹配成功,都可以用类似的逻辑获得完整的数据。
多表融合语句为结果集的处理提供了更强大灵活的功能。
3. 额外字段语句
额外字段语句的作用是在结果集合里加入一些额外的特殊字段,举例说明。页面内容:

-----------------------------------------------
'<a href="/book/url1.jsp?id=1">book1</a><br/>'
'<a href="/book/url2.jsp?id=2">book2</a><br/>'
'<a href="/book/url3. jsp?id=3">book3</a><br/>'
-----------------------------------------------

模式匹配语句:
-----------------------------------------------
页面配置:
	页面名 '小说列表页'
	匹配:'book''<a href="[$]?id=[$id]">[$bookName]</a><br/>';
-----------------------------------------------


用以上模式匹配语句可以从正文中提取获得如表3.9所示的数据。
表3.9  提取的数据
id BookName
1 book1
2 Book2
3 Book3


但是如果这个时候,我们想把 "/book/url1.jsp?id=1"这个URL存入某个字段,就没法在“模式匹配语句”里表达出来了,为了解决这个问题,可以把这个需求表达在IRQL的特殊处理语句里。可以这样写:小说列表页->book.href=>detailBookLink。其中,上述特殊语句又是由4个部分组成的:页面名->匹配名.href=>字段名。此特殊语句的含义是:把“小说列表页”这个页面上的book这个语句匹配到的文本内容中的URL保存为detailBookLink这个字段名。如果这个页面上的IRQL语句中有以上这个特殊处理语句,则最终的数据集合如表3.10所示。这样就得到了我们需要的各个结构化数据字段的值。
表3.10  数据集合
id BookName detailBookLink
1 book1 /book/url1.jsp?id=1
2 Book2 /book/url2.jsp?id=2
3 Book3 /book/url3.jsp?id=3


4. 页面别名声明语句
页面别名声明语句的作用是简化IRQL语句,把一个比较长的页面名或者匹配名用一个短小的单词代替,以便在以后的字段选择语句中的引用。
示例:

小说类列表页:P1,
详细信息页->bool:P2;

页面别名声明语句的格式是:

页面名||页面名->匹配名: 别名, 页面名2||页面名2->匹配名2: 别2…, 页面名N||页面名N->匹配名N: 别名N;

各个别名声明之间用“,”隔开,整个语句用“;”结束。
另外,可以用${parentPage}:P来表示当前页面的父页面,以及用${parentPage*2}:P来表示二级的父页面,依次类推,用${parentPage*N}:P表示N级父页面,具体含义将在本章最后的实例中更详细描述。
5. 字段选择语句
“字段选择语句”具有和SQL相似的格式,这个语句中指明了需要保存的字段信息,以及需要进行的额外处理。
示例:
	select P1->cateName,P2->bookName,P2->author,P3.status,P3.brief bookBrief 
where P2->author!='匿名'  and bookBrief is not NULL ;


以上语句的前半部分为select子句,用来描述结果数据集中所需的字段,后半部分为where子句,对于select子句获得的数据集合,可以用where子句进行过滤,去掉不符合条件的记录,这和SQL语言中的用法是完全一样的。
在解释以上语句之前,需要对爬虫遍历页面过程中获得的各种数据的结构进行说明。爬虫获得的数据是有层次性的,有3种不同层次类型的数据表,分别命名为共享表、独立表和继承表。
下一节中将具体阐述“共享表、继承表和独立表”这3种概念的意义与区别。
Global site tag (gtag.js) - Google Analytics