`
billy_zh
  • 浏览: 61813 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Nutch-0.9源代码:Injector类

阅读更多

出处:http://hi.baidu.com/shirdrn/blog/item/5d24ef2298e3eca24623e887.html

在对Nutch抓取工作流程分析中,已经简单地提及到了inject操作,如下所示:

inject操作调用的是nutch的核心包之一crawl包中的类org.apache.nutch.crawl.Injector。它执行的结果是:crawldb数据库内容得到更新,包括URL及其状态。

inject操作主要作用可以从下面3方面来说明:

(1) 将URL集合进行格式化和过滤,消除其中的非法URL,并设定URL状态(UNFETCHED),按照一定方法进行初始化分值;

(2) 将URL进行合并,消除重复的URL入口;

(3) 将URL及其状态、分值存入crawldb数据库,与原数据库中重复的则删除旧的,更换新的。


现在,根据上面的信息,可以进一步分析一下:

因为已经初始化了一个URL集合,那么这个集合中就存在多个URL,由此可以想到,如果由于输入错误可能导致错误的URL存在,所以inject操作需要对其进行检查核实,合法的才会去执行抓取,否则执行中发现是错误的会浪费CPU这宝贵资源。

另外,为了防止重复抓取URL,需要设定一个标志位来标识该URL完成抓取与否。那么这些信息应该被存放到某个地方,以备下次启动抓取工作的时候读取,存放到哪里呢?当然是CrawlDB了,更新已经初始化的CrawlDB实体的实例信息,对应于文件系统中的crawldb目录。


再考虑,如果本次抓取工作完成了,下次要启动了,同时也对应一个初始化的URL集合,那么这里面出现的URL可能在上次被抓取过,是否被抓取过,可以从CrawlDB中查看到详细的信息。对于重复的URL当然不希望再次被抓取(如果该URL对应的页面信息没有完全变更),应该忽略掉,这就涉及到了对抓取的页面去除重复的URL,这是应该做的,这也可以称为合并操作。


如果你了解MapReduce模型的话,现在已经能够想到,这里面可以实现MapReduce模型的,Nutch就实现了MapReduce模型(实际上是在Hadoop中实现的,因为对于每个Map和Reduce实现类都分别实现了org.apache.hadoop.mapred.Mapper接口与org.apache.hadoop.mapred.Reducer)。

Mapper实现对URL集合数据的映射,Reducer实现了对URL的合并操作。这里提及MapReduce模型,有助于对Injector类的两个静态内部类InjectMapper和InjectReducer理解。


org.apache.nutch.crawl.Injector类实现了org.apache.hadoop.util.ToolBase抽象类,如下所示:

public class Injector extends ToolBase

而org.apache.hadoop.util.ToolBase抽象类又实现了org.apache.hadoop.util.Tool接口。如果你对Tool类了解,及其配置部署过Hadoop自带的WordCount工具的时候,就理解了,实现Tool接口的实现类可以通过org.apache.hadoop.util.ToolRunner类来启动执行MapReduce任务的工具。


先看Injector类中如何实现Map的,InjectMapper类的实现如下所示:

  /** 标准化初始化的URLs,并且过滤注入的URLs */
public static class InjectMapper implements Mapper { // 实现Mapper接口,就要实现该接口中定义的map函数
    private URLNormalizers urlNormalizers; // URL标准化工具,可以实现URL的标准化
    private float interval; // 设置抓取间隔时间
    private float scoreInjected; // 设置注入URL对应页面的得分值
    private JobConf jobConf; // 抓取工作配置实例
    private URLFilters filters; // URL过滤器
    private ScoringFilters scfilters; // 得分过滤器
    private long curTime; // 设置注入时间

    public void configure(JobConf job) { // 为一次抓取工作进行配置
      this.jobConf = job;
      urlNormalizers = new URLNormalizers(job, URLNormalizers.SCOPE_INJECT);
      interval = jobConf.getFloat("db.default.fetch.interval", 30f);
      filters = new URLFilters(jobConf);
      scfilters = new ScoringFilters(jobConf);
      scoreInjected = jobConf.getFloat("db.score.injected", 1.0f);
      curTime = job.getLong("injector.current.time", System.currentTimeMillis());
    }

    public void close() {}

    public void map(WritableComparable key, Writable val,
                    OutputCollector output, Reporter reporter)
      throws IOException { // map函数的实现是核心
      Text value = (Text)val;
      String url = value.toString();              // 从初始化URL集合中读取一行,一行是一个URL
      // System.out.println("url: " +url);
      try {
        url = urlNormalizers.normalize(url, URLNormalizers.SCOPE_INJECT);       // 标准化URL
        url = filters.filter(url);             // 过滤URL,去除不合法的URL
      } catch (Exception e) {
        if (LOG.isWarnEnabled()) { LOG.warn("Skipping " +url+":"+e); }
        url = null;
      }
      if (url != null) {                          // 如果合法,则解析该URL
        value.set(url);                           // 将合法的URL收集到Text value对象中

         // 其中,org.apache.nutch.crawl.CrawlDatum类中定义了URL的各种可以设置的状态,可以在该类的对象中设置与URL相关的有用的信息,比如注入状态、抓取间隔时间,抓取时间、得分等等

        CrawlDatum datum = new CrawlDatum(CrawlDatum.STATUS_INJECTED, interval);
        datum.setFetchTime(curTime);
        datum.setScore(scoreInjected);
        try {
          scfilters.injectedScore(value, datum);
        } catch (ScoringFilterException e) {
          if (LOG.isWarnEnabled()) {
            LOG.warn("Cannot filter injected score for url " + url +
                     ", using default (" + e.getMessage() + ")");
          }
          datum.setScore(scoreInjected);
        }
        output.collect(value, datum); // 收集key/value对,并输出结果
      }
    }
}

 

从上面InjectMapper类的实现可以看出,其中包含的key应该是URL本身,而value则是与注入的URL对应的信息,比如URL当前状态信息(是否已经抓取过,或者不需要抓取)等等。


接着再看InjectReducer类,它实现了Reduce操作,代码如下所示:

  /** 为一个URL合并多个新的入口. */
public static class InjectReducer implements Reducer {
    public void configure(JobConf job) {}    
    public void close() {}

    public void reduce(WritableComparable key, Iterator values,
                       OutputCollector output, Reporter reporter)
      throws IOException { // reduce函数的实现也是核心的
      CrawlDatum old = null;
      CrawlDatum injected = null;
      while (values.hasNext()) { // 根据Map任务映射得到的迭代器,进行遍历得到的中间结果
        CrawlDatum val = (CrawlDatum)values.next();
        if (val.getStatus() == CrawlDatum.STATUS_INJECTED) { // 如果某个URL已经注入到CrawlDB
          injected = val;
          injected.setStatus(CrawlDatum.STATUS_DB_UNFETCHED); // 则设置这个URL对应的页面不用进行抓取
        } else {
          old = val; // 否则如果没有注入过,则需要对该URL对应的页面进行抓取
        }
      }
      CrawlDatum res = null;
      if (old != null) res = old; // 不要重写已经存在的value
      else res = injected;

      output.collect(key, res); // 收集key/value对;合并的最终结果是,使得将要注入到CrawlDB中URL没有重复的
    }
}

 
实现注入的操作是Injector类的inject()方法中,如下所示:

 public void inject(Path crawlDb, Path urlDir) throws IOException {

    if (LOG.isInfoEnabled()) {
      LOG.info("Injector: starting");
      LOG.info("Injector: crawlDb: " + crawlDb);
      LOG.info("Injector: urlDir: " + urlDir);
    }

    Path tempDir =
      new Path(getConf().get("mapred.temp.dir", ".") +
               "/inject-temp-"+
               Integer.toString(new Random().nextInt(Integer.MAX_VALUE))); // 临时目录用来存放MapReduce工作中生成的中间结果数据的

    // map text input file to a <url,CrawlDatum> file
    if (LOG.isInfoEnabled()) {
      LOG.info("Injector: Converting injected urls to crawl db entries.");
    }
    JobConf sortJob = new NutchJob(getConf());
    sortJob.setJobName("inject " + urlDir);
    sortJob.setInputPath(urlDir);
    sortJob.setMapperClass(InjectMapper.class);

    sortJob.setOutputPath(tempDir);
    sortJob.setOutputFormat(SequenceFileOutputFormat.class);
    sortJob.setOutputKeyClass(Text.class);
    sortJob.setOutputValueClass(CrawlDatum.class);
    sortJob.setLong("injector.current.time", System.currentTimeMillis());
    JobClient.runJob(sortJob);

    // merge with existing crawl db
    if (LOG.isInfoEnabled()) {
      LOG.info("Injector: Merging injected urls into crawl db.");
    }
    JobConf mergeJob = CrawlDb.createJob(getConf(), crawlDb);
    mergeJob.addInputPath(tempDir);
    mergeJob.setReducerClass(InjectReducer.class);
    JobClient.runJob(mergeJob);
    CrawlDb.install(mergeJob, crawlDb);

    // 删除临时文件
    FileSystem fs = new JobClient(getConf()).getFs();
    fs.delete(tempDir);
    if (LOG.isInfoEnabled()) { LOG.info("Injector: done"); }

}

 

该方法比较容易理解,在这里安装CrawlDB了,从而真正地将URLs注入到CrawlDB中了,更新crawldb目录中的数据。


要想执行inject操作,需要启动,这是在Injector类中的run()方法中启动的,如下所示:

  public int run(String[] args) throws Exception {
    if (args.length < 2) { // 根据命令行进行启动
      System.err.println("Usage: Injector <crawldb> <url_dir>");
      return -1;
    }
    try {
      inject(new Path(args[0]), new Path(args[1])); // 调用inject()方法
      return 0;
    } catch (Exception e) {
      LOG.fatal("Injector: " + StringUtils.stringifyException(e));
      return -1;
    }
}

 

最后,就是在main主函数中:

   public static void main(String[] args) throws Exception {
    int res = new Injector().doMain(NutchConfiguration.create(), args);
    System.exit(res);
}

 

其中,doMain()方法是在org.apache.hadoop.util.ToolBase抽象类中实现的,就是通过ToolRunner工具启动工作,如下所示:

 

 public final int doMain(Configuration conf, String[] args) throws Exception {
    return ToolRunner.run(conf, this, args);
}

 

启动inject操作,实际所做的工作就是对URL进行预处理,检查每个初始化URL的合法性,从而更新到CrawlDB中。待inject操作完成之后,就可以执行后继操作了——应该是生成抓取列表(generate操作)。

 

分享到:
评论

相关推荐

    Eclipse中编译Nutch-0.9

    ### Eclipse中编译Nutch-0.9:详解与步骤 #### 核心知识点概览 在本篇文章中,我们将深入探讨如何在Eclipse环境中编译Nutch-0.9,一个开源的网络爬虫项目,用于抓取互联网上的网页信息。文章涵盖的关键知识点包括...

    nutch-0.9 环境搭建所需最小cygwin

    1. **下载Nutch源码**:首先,从Apache官方网站或者镜像站点下载Nutch-0.9的源代码。将下载的源码解压到你想要的工作目录下,例如`C:\nutch\src\nutch-0.9`。 2. **配置环境变量**:打开Cygwin终端,设置必要的环境...

    nutch-2.1源代码

    在研究和使用Nutch-2.1源代码时,你可以深入了解搜索引擎的各个组成部分,如爬虫的实现、索引过程的细节、查询处理的算法等,这对于提升自己的搜索引擎技术知识非常有帮助。同时,Nutch也是研究搜索引擎优化(SEO)...

    apache-nutch-1.6-bin.tar.gz最新版

    在e盘下面出现nutch-0.9文件夹说明解压成功了.然后环境变量设置为NUTCH_JAVA_HOME=C:\Program Files\Java\jdk1.5.0(也就是说跟JAVA_HOME是相同的).测试nutch是否安装成功,只需要执行以下命令: $cd D:/Downloads/...

    apache-nutch-2.3.1-src.tar.gz

    `apache-nutch-2.3.1-src.tar.gz` 是 Apache Nutch 的源代码包,版本号为 2.3.1,以 tar.gz 格式压缩。 这个压缩包中包含的主要文件和目录结构如下: 1. **src**: 这是 Nutch 的源代码存放位置,分为多个子目录,...

    windows下nutch的安装.pdf

    安装完上述依赖后,将Nutch的源代码包下载到本地,解压至指定目录,如C:\nutch-0.9。解压后,需要修改nutch-site.xml文件以配置Nutch运行时的相关参数,例如配置抓取的用户代理名称: ```xml &lt;name&gt;...

    apache-nutch-2.2.1(Eclipse直接运行版)001

    apache-nutch-2.2.1(Eclipse直接运行版)今天刚做的,发现有很多坑,分享给大家实验,JDK1.7 Win10。我分享的两个压缩卷一起下载才可以用,资源限制太小了 002地址:...

    apache-nutch-1.7-src.tar.gz

    在“apache-nutch-1.7-src.tar.gz”这个压缩包中,你将获得Nutch 1.7的源代码,这使得开发者可以深入了解其工作原理,并对其进行定制和扩展。解压后的文件夹“apache-nutch-1.7”包含了所有必要的组件和配置文件。 ...

    apache-nutch-1.4-bin.tar.gz

    在这个"apache-nutch-1.4-bin.tar.gz"压缩包中,包含了运行 Nutch 的所有必要组件和配置文件,适合初学者和开发者快速部署和实验。 **Nutch 的核心组成部分:** 1. **爬虫(Spider)**:Nutch 的爬虫负责在网络中...

    nutch-windows-script:在 Windows 上运行 Nutch 的简单脚本

    - **Git**:获取nutch-windows-script项目的源代码。 - **Cygwin**或**Git Bash**:提供类似于Linux的命令行环境。 安装完这些依赖后,你可以按照以下步骤操作: 1. **克隆项目**:使用Git从GitHub上克隆“nutch-...

    nutch-web-api:用于 Apache Nutch 抓取应用程序的 RESTFul API

    nutch-web-api 它是什么 nutch-web-api是 Apache Nutch 爬虫应用程序的 RESTFul API 实现。 这个项目完全是用 node.js 和 coffeescript 编写的,目的是简化使用并提高灵活性。 REST API 不是 apache nutch 应用程序...

    apache-nutch-1.4

    - **配置文件**:Nutch的运行依赖于一系列配置文件,如`conf/nutch-site.xml`,用户可以通过修改这些文件来定制爬虫行为。 - **插件系统**:Nutch支持丰富的插件体系,如URL过滤器、解析器、索引器等,开发者可以...

    nutch配置nutch-default.xml

    nutch配置nutch-default.xml

    apache-nutch-1.3-src.tar.gz_nutch_nutch-1.3.tar.gz

    这个源码包 "apache-nutch-1.3-src.tar.gz" 和 "nutch-1.3.tar.gz" 包含了 Nutch 1.3 的源代码和编译后的二进制文件,对于开发者和研究者来说是非常有价值的资源。 **Nutch 概述** Nutch 是基于 Java 开发的,遵循 ...

    nutch 0.9 版(包含war,bin,src可直接部署使用)

    然后,根据项目需求,可以编辑配置文件(如conf/nutch-site.xml)来定制爬虫行为,如设置爬取策略、抓取频率、存储路径等。 7. **扩展性与集成**: Nutch的设计使其易于与其他系统集成,比如可以与Hadoop结合实现...

    Eclipse中编译Nutch-1.0

    接下来,需从官方网站下载Nutch-1.0的源代码压缩包(`nutch-1.0.tar.gz`),并进行解压。随后,在Eclipse中创建一个新的Java项目,命名可自定义,如“Nutch”,并在创建过程中选择“从现有源代码创建项目”选项,...

    apach-nutch-1.9-bin.tar.gz

    4. **配置与部署**:解压 "apache-nutch-1.9" 文件后,需要根据你的环境配置`conf/nutch-site.xml`文件,设置包括抓取间隔、并发度、存储路径等参数。同时,可能还需要配置`conf/regex-urlfilter.txt`和`conf/...

    apache-nutch-1.6-src.tar.gz

    这个`apache-nutch-1.6-src.tar.gz`文件包含了Nutch 1.6的源代码,允许开发者深入研究其内部机制,定制自己的爬虫需求,或者为项目贡献代码。 源代码包`apache-nutch-1.6`中通常包含以下几个关键部分: 1. **源...

    nutch 0.9分页代码(粘贴可用)

    ### Nutch 0.9 分页代码解析与应用 #### 一、背景介绍 Nutch 是一个开源的网络爬虫项目,它提供了高度可扩展且可靠的网页抓取框架。随着互联网的发展,数据量日益增大,如何高效地处理这些数据成为了一个重要的...

    Nutch1.7二次开发培训讲义

    - **环境变量配置:** 在项目属性中配置构建路径,添加源代码文件夹(src/java, src/test, src/testresources)以及配置类库路径(build和conf)。 **3. Ivy依赖管理** - **配置:** 使用IvyDE插件管理项目依赖,包括主...

Global site tag (gtag.js) - Google Analytics