小健讲座:搜索引擎与Web Spider原理详解 不指定

元创 , 2009/09/18 21:34 , SEO策略 , 锁定(0) , 阅读(2597) , Via 本站原创 | |
小健讲座:搜索引擎与Web Spider原理详解

网络蜘蛛(Web Spider)程序的实现是一个比较复杂而且有一些技术难点的工作,通过一段时间对其的研究,以及对完成一些数据抓取的用例进行了归纳总结,现详细说明给其实现原理及技术难点讲解给大家。
任意给一个入口即链接,便可以访问整个互联网,这就是网络蜘蛛(Web Spider)的最终目标,当然这对于像GOOGLE,BAIDU,yahoo等一些搜索引擎的蜘蛛来说,肯定是需要做到这一点的。
但对于我们目前的情况来说,不需要访问整个互联网,而我们只需要提取我们所需要的信息就可以了,那么对于网络蜘蛛(Web Spider)的关键点不是抓取网页数据,而是分析网页数据。
对于每个网页五花八门的数据格式,要分析出所需要的数据则是一件令人头痛的问题,接下来我们先说说整个实现流程,然后针对每一个步骤详细来说明
一下其实现原理及方法。
二. 网络蜘蛛基本原理
网络蜘蛛即 Web Spider,是一个很形象的名字呵呵。
把互联网比喻成一个蜘蛛网,那么Spider就是在网上爬来爬去的蜘蛛。
网络蜘.蛛是通过网页的链接地址来寻找网页,从网站某一个页面(通常是首页)开始爬入,读取网页的内容,找到在网页中的其它链接地址 ,然后通过这些链接地址寻找下一个网页,这样一直循环下去,直到把这个网站所有的网页都抓取完为止。

网络蜘.蛛是通过网页的链接地址来寻找网页,从网站某一个页面(通常是首页)开始爬入,读取网页的内容,找到在网页中的其它链接地址 ,然后通过这些链接地址寻找下一个网页,这样一直循环下去,直到把这个网站所有的网页都抓取完为止。
如果把整个互联网当成一 个网站,那么网络蜘蛛(Web Spider)就可以用这个原理把互联网上所有的网页都抓取下来。
网络蜘蛛实现的流程图如图:

点击在新窗口中浏览此图片

那好我继续往下讲从图中所看的设计原理。

三:网络蜘蛛实现的关键点

1.从上述流程图中我们可以看到,我们需要给定一个入口的URL,蜘蛛才开始工作。

这里我们就需要几个队列,来保存不同状态的链 接。

按照严格的分类,我们需要四个队列,即运行队列,等待队列,完成队列,异常队列,但针对具体情况,因为太多队列调度复杂 ,我们只用了二个队列,等待队列跟运行队列合并成为运行队列,完成队列,由于我们只针对特定的网站,所以异常队列的必要性不 是太大。

我们的线程一直从运行队列中读取最先写入队列的URL,如果存在,则往下执行,如果运行队列中没有数据了,则终止蜘蛛 的运行。

每处理完一个URL,则把其写入完成队列,防止重复访问。同时对于每个页面上合法并过滤后的链接都会写入运行队列。

对于一般的小程序,队列基本上用内存取存就可以了,但对于大型数据量而言,用内存保存数据肯定是不可取的,那么我们采取的是 用数据库模拟队列,即建了二个表,一为(RUNQUEUE)(运行队列),一为(SUCQUEUE)(完成队列)。

两表的字段相同,包括,队列ID ,用来判断链接的顺序,为先进先出做依据,队列URL 即链接内容,队列深度,即该链接所处的深度,用来判断在多少层终止数据抓 取。同时写了两个方法,一为取得最先进入队列的数据,二为移除该数据。

因此基本上模拟了队列的特征,可以进行海量数据的抓取 ,同时还可以进行断点续抓的功能。

2 超链接的获取及处理

对于任何网站的抓取,都少不了一个核心的东西,就是超链接,它是各个页面之间相互关联的钮带,也就是因为它,才把庞大的一个 互联网紧密的联系起来,使得各个页面之间不是孤立无助的。

对于超链接的获取来说,还有一个比较重要的问题,就是对于一个网站有太多的链接了,有外部链接,内部链接,绝对链接,相对的 等等形式的,如果我们不做任何处理的保存下来,那么我想这个蜘蛛就会永无止境的跑下去了,却不一定能获取得我们想要的数据, 因此这是不可取的。对于此问题,我们需要提供几个解决方法:

首先就是控制抓取层数,因为对于每一个链接,我们都给了它一个与之相对应的层数,如果这个层大于我们所给的层,那么就终止程 序;

第二个方法就是过滤关键字,就是对链接中的字词进行分析,过滤掉一些关键字,或保留相关关键字,这里也有二种方法:

第一就是只取得包含我们所给定的关键字的链接,比如说 (ITkafeiting) 我们只取得包含 (ITkafeiting) 这个词的链接,不包含的 我们就丢掉,这样所取的链接即为内部链接,并且这样的关键字是可以替加的,比如说我们要取得的链接中必须包含ITkafeiting 和 html 还是其它的都可以。

第二种方法就是取得不包含我们所给定的关键字的链接,同时该关键字也是可替加的,这样一来,我们就很容易的对抓取链接进行筛 选,获得我们需要的链接。

第三就是设置获取链接的个数,超过这个数字就终止;.

第四就是设置运行时间,一旦到时间就终止。因此现在只是采取了第一和第二种方法,对于每个页面上的链接的获得的方法有二种, 第一种就是用正则表达式,但这种方法我个人觉得不是太好,如果链接的格式不同,或者javascript 中的链接就不一定能抓得下来 ;第二种方法,就是用JAVA自带的解释HTML 的包HTMLEditorKit,这种方法我觉得不会漏掉任何的链接,不管是相对的还是绝对的, 同时效率比用正则表达式高,因此,我们基本上是采用这种方式。

对于链接的形式的不同,因为有相对的,绝对的,还有其它各种情况的,针对此问题,我特别写了一个方法,把所有的链接全部转换 成绝对的链接。这样那么就不会漏掉任何有用的数据。

对于链接过滤主要涉及两个数组,第一个数组即是必须存在的关键字组,这一数组中,可以根据具体的网站页面链接情况进行配置, 同时其数组的个数是无限制的,分析链接时,链接中必须存在这个数组中所有的关键字,如果有任何一个不存在,则都会丢弃该链接 。

如:该数组中有关键字,“http”, “ITkafeiting”, “html”,那么只有包含这些关键字的链接才有效,  http://www.itkafeiting.com/index.html该链接则是有效的,而 http://www.itkafeiting.com/index.asp这样的链接则会被丢弃, 并且该数组一定要配置;第二个数组则为不需要存在的关键字组,这一数组中,也是根据具体的网站页面链接情况进行配置的,同时 其数组个数也是无限制的,分析链接时,链接中必须不存在这个数组中的任何一个关键字,如果有任何一个存在,则会丢弃该链接。

如:该数组中有关键字,“asp”,那么 http://www.itkafeiting.com/index.asp则会被丢弃,该数组的配置是可选的,根据实际情 况可不配置,两个数组是同时使用的,进一步保证了链接的高过滤性。
21:01:14
为了避免死循环,防止重复抓取页面,除了上述过滤链接外,还需要判断,我们需要入库的链接是否存在,因此需要把该链接与数据 库中的队列表中的数据进行判断(运行队列和完成队列都要判断),如存在则丢弃,不存在则写入运行队列。


通过上述方法,就可以很好的,很方便,很灵活的提取我们需要的相关链接进行处理,从而避免了太多无用链接的麻烦。

(呵呵讲到这里有点累了,还是坚持一下,我继续往下讲.下面说一下页面内容抓取.)
通过从运行队列中取得的链接,则可以抓取该页面的所有源代码内容。这里主要应用到了 SUN 公司提供的NET 包。首先把链接先成  URL 实例,通过HTTPConnection 方法打开该链接,然后获得其页面内容的信息流。
再把该信息流转换成我们需要的字符串,这里面 有个问题是流只能应用一次,而在我们通过HTML 解析器获取其超链接的时候用的是流,因此没办法用二次流,经过思考先统一转成 字符串,然后在需要的时候,再把字符串转成流,从而达到我们的要求。

4.如何解析HTML 内容

当页面的内容抓取下来以后,那么接下来的事情就是解析 HTML 内容,并根据我们的需要提取相关的数据内容入库。

因为每个网站的风格各异,页面格式也各异,因此想做成一个通用的能解析所有网页的程序是不太可能的,那么这一部分就是比较灵 活的,需要我们根据不同的网站,以及我们所需的不同的内容进行灵活方便的配置,或者做小部分改动即可应用就很不错了。

因为 HTML 语言的特殊性,解析它是个非常麻烦的问题,通过比较发现采用正则表达式来分析HTML 是非常好的一种方式。因为在我 们的蜘蛛程序中,所有的解析都是采用正则表达式实现的。
通过对很多网站的内容进行分析以后,我们发现,解析后形成的结果无非 就是四种情况,借用表的形式来说明比较直观,即,单行单列,单行多列,多行单列,多行多列,因此,我们针对这四种情况分析写 了四个不同的方法,返回不同的结果及类型,同时针对不同的页面,可能出现这四种类型的嵌套,循环等形式,需要根据实际情况来 定。

同时根据网站不同,所取数据的不同,需要写一个或多个正则表达式。对于正则表达式的解析,我们采用开源项目组里的一个正则表 达式包,功能比较强大。同时基本上与微软的正则表达式的规则区别不是太大,因此,使用起来更方便。

5.数据入库

通过对页面内容的解析,就会提取到我们需要的数据,然后对数据进行优化,比如把全角转成半角,去掉其两边空格,
或对一些日期等进行格式化以后,基本上就入库了。入库的时候还需要针对不同的字段进行判断,该记录是否存在,如存在,
则放弃,尽可能提高入库数据的唯一性。

6 线程的实现意义及方法

对于网络蜘蛛而言,必须采用线程进行循环,因为这样可以提高效率,避免死循环,周期性运行而无需人工干预,易于
控制,易于采用多线程等。

当然采用线程也会有一些弊端,如网络阻塞的话,那么整个线程一直处于等待状态而导致死亡。

那么这里我们采用了一种线程监控的方法,就是说有二个线程在运行,一个是主线程,另一个是监控线程,监控线程每隔一段时间就去访问主线种与其共享的变量,一旦发现超时,即认为网络阻塞,于时杀掉线程,重新启动该线程。

避免了由于网络阻塞而线程一直等待的问题。

四:讲座结束语

以上的经验之谈纯属本人个人总结,希望能对一些朋友有所帮助。转载请完整保留此信息,如作修改,谢绝转载。我的讲座结束,谢谢大家支持。SEO公司 在职博士