Nutch 实战

初识 Nutch

本文介绍了开源搜索引擎Nutch的基本信息,并详细说明了在Eclispe下运行Nutch的步骤和需要注意的问题,并运行了一个实例对http://www.ibm.com/地址下的网页进行抓取。

宋伟 无需填写 无需填写(songwwei@cn.ibm.com), 软件工程师, EMC

2008 年 11 月 20 日

  • +内容

基本信息

Nutch是一个开放源代码(open-source)的Java搜索引擎包,它提供了构建一个搜索引擎所需要的全部工具和功能。使用Nutch不仅可以建立自己内部网的搜索引擎,同时也可以针对整个网络建立搜索引擎。除了基本的功能之外,Nutch也还有不少自己的特色,如Map-Reduce、Hadoop、Plugin等。

Nutch的总体结构

Nutch从总体上看来,分为三个主要的部分:爬行、索引和搜索,各部分之间的关系如图1所示。Web db是Nutch初始运行的URL集合;Fetcher是用来抓取网页的爬行器,也就是平时常说的Crawler;indexer是用来建立索引的部分,它将会生成的索引文件并存放在系统之中;searcher是查询器,用来完成对某一词条的搜索并返回结果。

图 1. Nutch 总体结构
Nutch 总体结构

Nutch 的运行流程

在了解了 Nutch 的总体结构之后,再详细的看看 Nutch 具体是如何运行的?Nutch 的运行流程如图2所示。

1. 将起始 URL 集合注入到 Nutch 系统之中。

2. 生成片段文件,其中包含了将要抓取的 URL 地址。

3. 根据URL地址在互联网上抓取相应的内容。

4. 解析所抓取到的网页,并分析其中的文本和数据。

5. 根据新抓取的网页中的URL集合来更新起始URL集合,并再次进行抓取。

6. 同时,对抓取到的网页内容建立索引,生成索引文件存放在系统之中。

图 2. Nutch 的运行流程
Nutch 的运行流程

从用户端来看,Nutch 提供了一个基于 Tomcat 的应用程序,它允许用户输入词条,然后 Nutch 会在已经建立好的索引文件中进行搜索,并将相应的结果返回给用户。

Nutch 的配置和运行

Nutch 既可以在 Linux 下运行,可以在 Windows 下运行,同时还可以在 Eclipse 环境中运行。在本部分中,主要介绍如何在 Eclipse 环境下运行 Nutch。

下载 Nuch 软件包

首先,应该在 Nutch 的下载页面中下载相应的Nutch软件包,现在最新的版本号是0.9, 通常使用的版本号是 0.8.1。

解压缩

下载后得到的是一个名为 nutch-0.9.tar.gz 的压缩包,使用7-Zip可以将其解压缩,解压后得到的文件结构如图3所示。

图 3. Nutch 的目录结构
Nutch 的目录结构

在bin文件夹下存放的是用于命令行运行的文件;Nutch的配置文件都放在了conf下,lib是一些运行所需要的jar文件;plugins下存放的相应的插件;在src文件夹中的是Nutch的所有源文件;webapps文件夹中存放的是web运行相关文件;nutch-0.9.war是Nutch所提供的基于Tomcat的应用程序包。

导入源代码

在获得Nutch的源代码之中,就可以将其导入到Eclipse环境中,并生成一个新的java工程。导入后的代码结构如图4所示。在导入过程中应该注意的是,需要把lib下的所有jar文件以及conf文件夹都添加到工程的build path之中。

另外,Nutch还需要另外两个jar文件,jid3lib-0.5.1.jar和rtf-parser.jar,请分到到下面两个链接下载。

http://nutch.cvs.sourceforge.net/nutch/nutch/src/plugin/parse-mp3/lib/

http://nutch.cvs.sourceforge.net/nutch/nutch/src/plugin/parse-rtf/lib/

图 4. Nutch 的包结构
Nutch 的包结构

配置

在正式开始运行Nutch之前,还需要做一些必要的配置,不然在运行时会出错,无法按照要求抓取到相应的页面。

第一个需要修改的文件是 nutch-default.xml, 需要将 HTTP properties 部分的 http.agent.name 赋予一个有意思的字符串;还需要将 plugin properties 部分的 plugin.folders 按照具体的情况做必要修改。清单 1 和清单 2 分别是本文中的 Demo 运行时的具体配置情况,供大家参考。

清单1.
<!-- HTTP properties -->
  <name>http.agent.name</name>
  <value>testNutch</value>
  <description>Just for Testing
  </description>
</property>
清单2.
<!-- plugin properties -->
<property>
  <name>plugin.folders</name>
  <value>plugin</value>
  <description>Directories where nutch plugins are located.  Each
  element may be a relative or absolute path.  If absolute, it is used
  as is.  If relative, it is searched for on the classpath.</description>
</property>

其次,需要修改的文件是crawl-urlfilter.txt, 将其中的MY.DOMAIN.NAME部分按照实际的域名进行修改。清单3中的配置是对*.ibm.com/域进行抓取。

清单3.
# accept hosts in MY.DOMAIN.NAME
+^http://([a-z0-9]*\.)*ibm.com/

另外,还需要的一个操作是在conf文件夹下,建立一个名为prefix-urlfilter.txt的文本文件,其中的内容很简单,如清单4所示。

清单4.
# prefix-urlfilter.txt file starts here
http
# prefix-urlfilter.txt file ends here

抓取

在配置完成之后,就可以开始运行Nutch的Crawler了,不过,正如本文前面所述,开始运行前还需要设定初始URL集合。具体的方法是建立一个文件夹(本文建立的文件夹名为url),并在其中建立一个纯文本文件(本文建立的文件名为urls.txt),文件文件中存放了需要抓取的其实URL地址,如“http://www.ibm.com/”。

然后在org.apache.nutch.crawl包下的Crawl.java文件上点击右键,选择“Run as”,再选择“open run dialog”,在如图5所示的对话框中输入运行参数,然后点击“Run”。这样系统就可以运行了。

图 5. 运行 Crawler
运行 Crawler

在运行过程中,会出现很多的log信息,图6和图7是系统运行过程中的一些截图,从中可以看出正在抓取的网页URL地址和抓取速度等一些信息。等抓取任务成后,系统会自动生成相应的索引文件,以后查询器使用。在以后的文章中,会深入探讨相应的话题。

图 6. Nutch 运行信息 1
Nutch 运行信息 1
图 7. Nutch 运行信息 2
Nutch 运行信息 2

深入分析 Crawl 源代码

在了解了 Nutch 的运行过程之后,再来分析 Nutch 内部的运行流程是什么样子的,以及各个类之间是如何协同配置的?

Crawl的入口

正如在前文中所提到的,在运行 Crawl 时需要输入一些必要的参数,并且格式也是一定的。具体的用法是 Crawl <urlDir> [-dir d] [-threads n] [-depth i] [-topN N]。其中,<urlDir> 是必须有的参数;Crawl 是运行的主文件;-dir 表示存放的目标文件夹;-threads 表示抓取过程中其中的线程数;-depth 表示要抓取的深度层次。

如果在运行时不指定这些参数,那么Nutch会默认设定这个参数值。详见清单。

清单 5.
   Path dir = new Path("crawl-" + getDate());
    int threads = job.getInt("fetcher.threads.fetch", 10);
    int depth = 5;
int topN = Integer.MAX_VALUE;

如果指定了运行参数,Nutch会按照以下的方式来处理。

清单 6.
for (int i = 0; i < args.length; i++) {
      if ("-dir".equals(args[i])) {
        dir = new Path(args[i+1]);
        i++;
      } else if ("-threads".equals(args[i])) {
        threads = Integer.parseInt(args[i+1]);
        i++;
      } else if ("-depth".equals(args[i])) {
        depth = Integer.parseInt(args[i+1]);
        i++;
      } else if ("-topN".equals(args[i])) {
        topN = Integer.parseInt(args[i+1]);
        i++;
      } else if (args[i] != null) {
        rootUrlDir = new Path(args[i]);
      }
}

生成目标文件夹

在设定运行参数后,经过一个必要的处理,Nutch会生成若干个目标文件夹用来存储不同的文件内容,具体包括:crawlDb,linkDb,segments,indexes和index。

清单 7.
    Path crawlDb = new Path(dir + "/crawldb");
    Path linkDb = new Path(dir + "/linkdb");
    Path segments = new Path(dir + "/segments");
    Path indexes = new Path(dir + "/indexes");
Path index = new Path(dir + "/index");

注入、抓取和更新

当生成了所需要的目标文件夹之后,Nutch就可以开始抓取工作了。当然,在抓取网页过程中会使用功能类来完成相应的单元工作。具体来讲,在注入、抓取和更新过程中,会用来的功能类有Injector、Generator、Fetcher、ParseSegment和CrawlDb。

整个过程分为以下几个步骤:

注入
injector.inject(crawlDb, rootUrlDir);
抓取
Path segment = generator.generate(crawlDb, segments, -1, topN, System
          .currentTimeMillis(), false, false);
      if (segment == null) {
        LOG.info("Stopping at depth=" + i + " - no more URLs to fetch.");
        break;
      }
      fetcher.fetch(segment, threads);
更新
if (!Fetcher.isParsing(job)) {
        parseSegment.parse(segment);  
      }
      crawlDbTool.update(crawlDb, new Path[]{segment}, true, true);

4. 反转、索引、去重及合并

最后的工作就是生成索引,去重并合并索引。不过,现在一般都是会生成倒排索引文件,所以在建立索引之前还会有一个反转的操作,如清单所示。

清单 8.
linkDbTool.invert(linkDb, segments, true, true, false); // invert links

      // 索引
      indexer.index(indexes, crawlDb, linkDb, fs.listPaths(segments));
      //去重
      dedup.dedup(new Path[] { indexes });
      //合并
      merger.merge(fs.listPaths(indexes), index, tmpDir);

总结

本文主要介绍了使用Nutch进行网页抓取和建立索引方面的内容,首先分析了网页抓取的过程,然后结合源代码分析了整个抓取过程的组织和实现。当然了,Nutch是一款功能非常丰富的开源搜索引擎,关于其他方面的内容,将在后面的文章中一一介绍。

参考资料

展开阅读全文

没有更多推荐了,返回首页