项目中要对指定的网络资源进行抓取、存储、分类、索引、并提供检索服务。充当全文检索数据库的是Apache组织下的开源项目Lucene 检索工具,而Lucene只是个搜索引擎工具,它提供API接口,通过编写程序对信息进行索引和检索,在其后台需要网络爬虫程序的支持,其目的是通过网络爬虫软件抓取网页,作为提供给Lucene搜索引擎的资源,进行索引和查询。
Nutch http://nutch.apache.org/
Heritrix http://crawler.archive.org/
Nutch 是 Apache 基金会的一个开源项目,它原本是开源文件索引框架 Lucene 项目的一个子项目,后来渐渐发展成长为一个独立的开源项目。它基于 Java 开发,基于 Lucene 框架,提供 Web 网页爬虫和搜索引擎两部分功能。
Nutch主要分为两个部分:网页爬虫(Crawler)和搜索引擎(Searcher)。Crawler主要用于从网络上抓取网页并为这些网页建立索引。Searcher主要利用这些索引检索用户的查找关键词来产生查找结果。另外很吸引人的一点在于,它提供了一种插件框架,使得其对各种网页内容的解析、各种数据的采集、查询、集群、过滤等功能能够方便的进行扩 展,正是由于有此框架,使得 Nutch 的插件开发非常容易,第三方的插件也层出不穷,极大的增强了 Nutch 的功能和声誉。
Nutch爬虫的工作策略一般则可以分为累积式抓取(cumulative crawling)和增量式抓取(incremental crawling)两种。
累积式抓取是指从某一个时间点开始,通过遍历的方式抓取系统所能允许存储和处理的所有网页。在理想的软硬件环境下,经过足够的运行时间,累积式抓取的策略可以保证抓取到相当规模的网页集合。但由于Web数据的动态特性,集合中网页的被抓取时间点是不同的,页面被更新的情况也不同,因此累积式抓取到的网页集合事实上并无法与真实环境中的网络数据保持一致。
增量式抓取是指在具有一定量规模的网络页面集合的基础上,采用更新数据的方式选取已有集合中的过时网页进行抓取,以保证所抓取到的数据与真实网络数据足够接近。进行增量式抓取的前提是,系统已经抓取了足够数量的网络页面,并具有这些页面被抓取的时间信息。
面向实际应用环境的网络蜘蛛设计中,通常既包括累积式抓取,也包括增量式抓取的策略。累积式抓取一般用于数据集合的整体建立或大规模更新阶段;而增量式抓取则主要针对数据集合的日常维护与即时更新。
在确定了抓取策略之后,如何从充分利用网络带宽,合理确定网页数据更新的时间点就成了网络蜘蛛运行策略中的核心问题。
总体而言,在合理利用软硬件资源进行针对网络数据的即时抓取方面,已经形成了相对比较成熟的技术和实用性解决方案,这方面目前所需解决的主要问题,是如何更好的处理动态网络数据问题(如数量越来越庞大的Web2.0数据等),以及更好的根据网页质量修正抓取策略的问题。
Nutch架构图
Nutch工作流程图
Nutch工作流程:
建立初始URL集合分析
初始URL集的建立有两种方式:超链接和站长提交。
超链接是指机器人程序根据网页链到其他网页中的超链接,就像日常生活中所说的“一传十,十传百……”一样,从少数几个网页开始,连到数据库上所有到其他网页的链接。理论上,若网页上有适当的超连结,机器人便可以遍历绝大部分网页。
站长提交是指在实际运行中,爬虫不可能抓取到所有站点,为此,网站站长可以向搜索引擎进行提交,要求收录,搜索引擎经过核查之后,便将该网站加入到URL集合中,进行抓取。
1. inject操作分析
inject操作调用的是Nutch的核心包之一crawl包中的类org.apache.nutch.crawl.Injector。它执行的结果是:crawldb数据库内容得到更新,包括URL及其状态。
inject操作主要作用可以从下面3方面来说明:
(1) 将URL集合进行格式化和过滤,消除其中的非法URL,并设定URL状态(UNFETCHED),按照一定方法进行初始化分值;
(2) 将URL进行合并,消除重复的URL入口;
(3) 将URL及其状态、分值存入crawldb数据库,与原数据库中重复的则删除旧的,更换新的。
2. generate操作分析
generate操作调用的是crawl包中的类org.apache.nutch.crawl.Generator。它执行的结果是:创建了抓取 列表,存放于segments目录下,以时间为文件夹名称。循环抓取多少次,segments文件夹下就会有多少个以时间为名称的文件夹。
generate操作主要作用可以从下面3方面来说明:
(1) 从crawldb数据库中将URL取出并进行过滤;
(2) 对URL进行排序,通过域名、链接数和一种hash算法综合进行降序排列;
(3) 将排列列表写入segments目录中。
3. fetch操作分析
fetch操作调用的是fetcher包中的类org.apache.nutch.fetcher.Fetcher。它执行的结果是:将页面内容抓取下来,存于segment目录下。
fetch操作主要作用可以从下面4方面来说明:
(1) 执行抓取,按照segments目录下的抓取列表进行;
(2) 抓取过程中,页面的URL地址可能因为链接发生改变,从而需要更新URL地址;
(3) 抓取采用多线程方式进行,以提高抓取速度;
(4) fetch操作过程中调用了parse操作。
4. parse操作分析
parse操作调用的是parse包中的类org.apache.nutch.parse.ParseSegment。它执行的结果是:将fetch得到的页面解析为text和data,存于segments目录下。
parse操作主要作用可以从下面3方面来说明:
(1) 解析segment中由fetch得到的页面,并进行整理,将页面分成为parse-date和parse-text;
(2) parse-date中保存的是页面的题名、作者、日期、链接等内容;
(3) parse-text中保存的是页面的文本内容。
例如,我只执行一次抓取任务,就执行了上述的一些操作,操作的结果直接反映在segments目录中。可以看到在home/SHIYANJUN /nutch-0.9/mydir/segments目录下面创建了20081004102407这个目录,该目录中包含6个目录:content、 crawl_fetch、crawl_generate、crawl_parse、parse_data、parse_text,从目录名称就可以大致知道该目录存取的相关内容信息。
5. updatedb操作分析
updatedb操作调用的是crawl包中的类org.apache.nutch.crawl.CrawlDb。它执行的结果是:更新了crawldb数据库,为下一轮抓取做准备。
updatedb操作主要作用如下:
根据segments目录下fetch目录和parse目录中的内容,对crawldb进行更新,增加新的URL,更换旧的URL。
6. invertlinks操作分析
invertlinks操作用来更新linkDB,为建立索引的工作提供准备。
7. index过程分析
index过程,即索引过程,包括:将数据转换成文本、分析文本、将分析过的文本保存到数据库中这三个操作。
(1) 转换成文本
在索引数据之前,首先必须将数据转换成Nutch 能够处理的格式――纯文本字符流。但是,在现实世界中,信息多以富媒体(rich media)文档格式呈现:PDF、WORD、EXCEL、HTML、XML等。为此,Nutch采用了插件机制(plugin),通过各种各样的文档解 析器,将富媒体转换成纯文字字符流。文档解析器种类繁多,开发人员可以根据需要进行选择,同时还可以自己修改或编写,非常灵活方便。
(2) 分析文本
在对数据进行索引前,还需要进行预处理,对数据进行分析使之更加适合被索引。分析数据时,先将文本数据切分成一些大块或者语汇单元 (tokens),然后对它们执行一些可选的操作,例如:在索引之前将这些语汇单元转换成小写,使得搜索对大小写不敏感;最有代表性的是要从输入中去掉一 些使用很频繁但却没有实际意义的词,比如英文文本中的一些停止词(a、an、the、in、on等)。同样的,我们也需要分析输入的语汇单元,以便从词语中去掉一些不必要的字母以找到它们的词干。这一处理过程称为分析(analyze)。分析技术在索引和搜索时都会用到,比较重要。
(3) 将分析过的文本保存到数据库中
对输入的数据分析处理完成之后,就可以将结果写入到索引文件中。Nutch采用的是Lucene的索引格式,可以参考关于Lucene的索引机制。Lucene采用“倒排索引”的数据结果来存储索引的。
8. 搜索程序分析
Nutch的搜索程序执行过程,可以从下面的步骤了解:
(1) HTTP服务器接收用户发送过来的请求。对应到Nutch的运行代码中就是一个servlet,称为查询处理器(Query Handler)。查询处理器负责响应用户的请求,并将相应的HTML结果页面返回给用户。
(2) 查询处理器对查询语句做一些微小的处理并将搜索的项(terms)转发到一组运行索引搜索器的机器上。Nutch的查询系统似乎比lucene简单的多, 这主要是因为搜索引擎的用户对他自己所要执行的查询内容有非常清晰的思路。然而,lucene的系统结构非常灵活,且提供了多种不同的查询方式。看似简单的Nutch查询最终被转换为特定的lucene查询类型。每个索引搜索器并行工作且返回一组有序的文档ID列表。
(3) 现在存在这大量从查询处理器返回过来的搜索结果数据流。查询处理器对这些结果集进行比较,从所有的结果查找出匹配最好的那些。如果其中任何一个索引搜索器在1~2秒之后返回结果失败,该搜索器的结果将被忽略。因此,最后列表由操作成功的搜索器返回的结果组成。
关于查询处理器
查询处理器对查询作了一些细微的处理,例如删除停止词(例如the、of等)。接着Nutch需要执行一些操作以便于它在大规模的数据环境下能更好的工作。一个索引搜索器涉及搜索的文档集数目非常庞大,所以Nutch需要同时与很多索引搜索器交互来提高搜索速率。实际运行环境中,为了保证系统级别的稳定性,文档集的段文件会被复制到多个不同主机上。因为对于文档集中的每个段,查询处理器会随机的与其中一个可搜索到自身的索引搜索器相交互。如果发现一个索引搜索器不能交互,查询处理器会通知之后的搜索操作不使用该搜索器,但是查询处理器每隔一段时间会回头检查一次搜索器的状态,以防该主机上的搜索器再次可用。
关于分析器
Nutch使用自己的分析器,对应于analysis包。Nutch把索引时进行分析所使用的二元语法技术(bigram)与查询过程中对短语的优化技术结合在一起,通过二元语法技术可以把两个连续的词组合成一个语汇单元。这就可以大大减少搜索时需要考虑的文档范围,例如,包含词组the quick的文档比包含the 的文档要少的多。
分析器对分析操作进行了封装。分析器通过执行若干操作,将文本语汇单元化,这些操作可能包括提取单词、去除标点符号、去掉语汇单元上的音调符号、将字母转化为小写(也称为规格化)、移除常用词、将单词转换为词干形式(词干还原),或者将单词转换为基本形等。这个过程也称为语汇单元化过程。分析操作发生在两个阶段:建立索引和进行查询时。
Nutch的其他一些特性
● 为了获取小数量的文档(通常是10个左右),查询处理器会对每个索引搜索器进行查询。因为最后的结果是从多个索引搜索器中合并得到的,所以就没有必要从一个数据源中获取过多的文档结果,尤其是在用户很少去查看第一页之后的结果的情况下。
● 实际上,在每个用户查询被处理之前,它会被扩展为十分复杂的lucene查询。每个索引过的文档都包含了三个域:网页自身的内容,网页的URL文本值,以及由所有关键(anchor)文本所组成的合成文档,这些关键文本可在导航网页的超链接中找到。每个域对应一个不同的权重值。Nutch的查询处理器生成一个lucene布尔查询,其中在三个域中都包含了搜索引擎用户所输入的文本。
● Nutch也会特别的把那些在web上出现的非常频繁的关键字组作为一个整体来索引(其中的许多关键字是与HTTP相关的词组)。这些关键字序列出现的非常频繁,所以无需花费精力去对这些词序中的每个组成部分单独搜索,也不必查找出这些搜索结果中是否有交集的部分。我们不用把这些项划分为单独的单词对来搜索文档,而是把它们作为一个单元,当然前提是Nutch在索引期间必须检测到它们是作为一个整体而存在的。另外,在与索引搜索器交互之前,查询处理器会查找出用户输入的字符串中单词的任意组合。如果这样一个词序确实存在,它的单词成员就会整合成一个特殊的搜索项。
● 在使用lucene执行索引操作之前,Nutch的内容获取器/索引器需要预处理HTML文档。它使用NekoHTML解析器剥离HTML中的内容,并索引其中的非标记文本。对于从HTML文档提取标题文本,NekoHTML是很有建树的。
● Nutch进程间通信层(IPC)保持了查询处理器与索引搜索器间长时间的连接。查询处理器端可能存在多个并发的线程,对于给定的地址,任一线程都可以向远程服务器发送调用请求。服务器每接受一个请求之后,就会根据给定字符串尝试去查找对应的注册服务(运行在自己线程上)。客户端的请求线程会一直阻塞其他事件,直到服务器端响应的IPC代码到达后,消息通知请求线程为止。如果服务器的响应花费的时间超过了IPC规定的时限,IPC的代码就会宣布此服务器不可用,并抛出一个异常。
● 另外,Nutch的排序算法是仿照Google的PageRank算法,关于PageRank算法的资料有很多,推荐《Google的秘密PageRank彻底解说中文版》。
Nutch支持分布式抓取,并有Hadoop支持,可以进行多机分布抓取,存储和索引。另外很吸引人的一点在于,它提供了一种插件框架,使得其对各种网页内容的解析、各种数据的采集、查询、集群、过滤等功能能够方便的进行扩展,正是由于有此框架,使得 Nutch 的插件开发非常容易,第三方的插件也层出不穷,极大的增强了 Nutch 的功能和声誉。
Nutch的爬虫定制能力比较弱
Heritrix,是www.archive.org 上的开源产品,出色之处在于它的可扩展性,可以扩展它的组件,来实现自定义的抓取逻辑,但配置比较复杂。Heritrix在抓取中可以获取完整、精确的站点内容的复制。包括文本和非文本信息,抓取并存储内容,不对页面进行内容上的修改。在抓取速度上慢、需要大容量存储空间和宽速网络。重新爬行对相同的URL不进行替换。Heritrix 有 Web 控制管理界面,进行启动、监控。
Heritrix架构图
Heritrix流程图
Heritrix的工作流程是一个循环,具体流程是:
1 在预定的URI中选择一个。
2 从选择的URI的网址下载远程文件
3 分析,归档下载到的内容
4 从分析到的内容里面选择感兴趣的URI。加入预定队列。
5 标记已经处理过的URI
CrawlController(下载控制器)
整个下载过程的总的控制者,整个抓取工作的起点,决定整个抓取任务的开始和结束。从Frontier获取URI,传递给线程池(ToePool)中的ToeThread处理。
Frointier(边界控制器)
主要确定下一个将被处理的URI,负责访问的均衡处理,避免对某一web服务器造成太大的压力。
它保存着crawl的状态:
(1)发现的URI(URIs have been discovered)
(2)正在被处理的URI(URIs are being processed (fetched))
(3)已经处理的URI(URIs have been processed)
TeoThread(处理线程)
Heritrix是多线程的,每一个URI被一个ToeThread处理。
Processor(处理器)
下图为处理器的整个结构图
许多Processor组成一个处理链(processor chains)中,每一个处理链对URI进行一系列的处理。
(1)Pre-fetch processing chain(预处理链)
主要根据robot协议,DNS以及下载范围控制信息判断当前URI是否应当处理。
(2)Fetch processing chain(抓取处理链)
从远程服务器获取数据
(3) Extractor processing chain(抽取处理链)
从网页中抽取新的URI
(4)Write/index processing chain(写处理链)
负责把数据写入本地磁盘
(5)Post-processing chain(后置处理链)
由CrawlStateUpdater,LinksScoper,FrontierScheduler构成。
Heritrix主要有三大部件:范围部件,边界部件,处理器链
范围部件:主要按照规则决定将哪个URI入队。
边界部件:跟踪哪个预定的URI将被收集,和已经被收集的URI,选择下一个 URI,剔除已经处理过的URI。
处理器链:包含若干处理器获取URI,分析结果,将它们传回给边界部件
Heritrix的其余部件有:
WEB管理控制台:大多数都是单机的WEB应用,内嵌JAVA HTTP 服务器。 操作者可以通过选择Crawler命令来操作控制台。
Crawler命令处理部件:包含足够的信息创建要爬的URI。
Servercache(处理器缓存):存放服务器的持久信息,能够被爬行部件随时查到,包括IP地址,历史记录,机器人策略。
处理器链:
预取链:主要是做一些准备工作,例如,对处理进行延迟和重新处理,否决随后的操作。
提取链:主要是获得资源,进行DNS转换,填写请求和响应表单
抽取链:当提取完成时,抽取感兴趣的HTML,JavaScript,通常那里有新的也适合的URI,此时URI仅仅被发现,不会被评估
写链:存储爬行结果,返回内容和抽取特性,过滤完存储。
提交链:做最后的维护,例如,测试那些不在范围内的,提交给边 界部件
Heritrix 1.0.0包含以下关键特性:
1. 用单个爬虫在多个独立的站点一直不断的进行递归的爬。
2. 从一个提供的种子进行爬,收集站点内的精确URI,和精确主机。
3. 主要是用广度优先算法进行处理。
4. 主要部件都是高效的可扩展的
良好的配置,包括:
1. 可设置输出日志,归档文件和临时文件的位置
2. 可设置下载的最大字节,最大数量的下载文档,和最大的下载时间。
3. 可设置工作线程数量。
4. 可设置所利用的带宽的上界。
5. 可在设置之后一定时间重新选择。
6. 包含一些可设置的过滤机制,表达方式,URI路径深度选择等等。
Heritrix的爬虫定制参数多
单实例的爬虫,之间不能进行合作。在有限的机器资源的情况下,却要复杂的操作。只有官方支持,仅仅在Linux上进行了测试。每个爬虫是单独进行工作的,没有对更新进行修订。在硬件和系统失败时,恢复能力很差。很少的时间用来优化性能。
相对于Nutch,Heritrix仅仅只是一个爬虫工具,没有提供搜索引擎。如果要对抓取的站点排序必须要实现类似于Pagerank的复杂算法。
Web-Harvest http://web-harvest.sourceforge.net
Crawler4j http://code.google.com/p/crawler4j/
Web-Harvest是一个Java开源Web数据抽取工具。它能够收集指定的Web页面并从这些页面中提取有用的数据。Web-Harvest主要是运用了像XSLT,XQuery,正则表达式等这些技术来实现对text/xml的操作。
Crawler4j是一个开源的Java类库提供一个用于抓取Web页面的简单接口。可以利用它来构建一个多线程的Web爬虫。
Nutch 只获取并保存可索引的内容。Heritrix则是照单全收。力求保存页面原貌
Nutch 可以修剪内容,或者对内容格式进行转换。
Nutch 保存内容为数据库优化格式便于以后索引;刷新替换旧的内容。而Heritrix 是添加(追加)新的内容。
Nutch 从命令行运行、控制。Heritrix 有 Web 控制管理界面。
Nutch 的定制能力不够强,不过现在已经有了一定改进。Heritrix 可控制的参数更多。
Heritrix 是个 "archival crawler" -- 用来获取完整的、精确的、站点内容的深度复制。包括获取图像以及其他非文本内容。抓取并存储相关的内容。对内容来者不拒,不对页面进行内容上的修改。重新爬行对相同的URL不针对先前的进行替换。爬虫通过Web用户界面启动、监控、调整,允许弹性的定义要获取的URL。
Nutch支持分布式抓取,Heritrix仅支持单机抓取,不能多机协同工作。
crawler |
功能单一 |
支持分布式爬取 |
定制能力 |
镜像保存 |
Nutch |
× |
√ |
弱 |
× |
Heritrix |
√ |
× |
强 |
√ |
考察垂直爬虫的几个原则:
性能较高:较好支持多线程并发处理;支持异步、非阻塞socket;支持分布式爬取;爬取调度算法性能较高;内存使用效率较高,不要老是出现out of memory问题;
架构优美:组件式设计式架构,扩展方便;架构设计精巧。至少值得花时间去学习架构设计思想。
扩展方便:能够与现有框架较好集成;由于是垂直爬虫,需要针对不同的网页定制爬取规则集逻辑,需要能够方便测试,不要老是重新编译,因此最好支持python等脚本语言
功能全面:内置支持ajax/javascript爬取、登录认证、深度爬取设置、页面压缩处理等
管理功能:提供爬虫管理接口,能够实时监控和管理爬取
调研结果:
如果开发一个基于Pagerank或OPIC(On-Line Page Importance Computation)网页排序算法的搜索引擎,且不用对站点图片进行存储的搜索引擎可以用Nutch。Nutch本身就是一个网络搜索引擎解决方案,它分为抓取部分与搜索部分,并且实现了OPIC算法。
如果要开发一个可定制的、比较复杂的并要对站点进行深度复制,对网络资源进行长期保存的搜索引擎,可以使用Heritrix+Lucene。
个人感觉还是用Nutch比较好些。因为开发强度也比较小,如果仅仅只对某几个网站进行垂直搜索,且对网站数据的排序只与检索词相关度有关,不涉及PageRank,可以使用Heritrix+lucene.因为要在短时间实现PageRank算法并且成熟应用是比较困难的.且Heritrix本身不支持分布式抓取。