Heritrix架构学习笔记(二)

2、中央控制器CrawlController

该类是一次抓取任务中的核心组件。塔将决定整个抓取任务的开始和结束。

org.archive.crawler.framework
Class CrawlController

java.lang.Object
      
      

      
      
      
      
       
          
        
        
  
      
      org.archive.crawler.framework.CrawlController
      
      

在它的Field声明中,看到的一部分代码,如下图所示:

public class CrawlController implements Serializable, Reporter {

     ……

    // key subcomponents which define and implement a crawl in progress

    private transient CrawlOrder order;

    private transient CrawlScope scope;

    private transient ProcessorChainList processorChains;

   

    private transient Frontier frontier;

 

    private transient ToePool toePool;

   

    private transient ServerCache serverCache;

   

    // This gets passed into the initialize method.

    private transient SettingsHandler settingsHandler;

下面让我们来解释一下这几个组件:

l         CrawlOrder:它保存了对该次抓取任务中order.xml的属性配置。

l         CrawlScope:决定当前抓取范围的一个组件。

l         ProcessorChainList:从名称上可知,其表示处理器链。

l         Frontier:它是一个URL的处理器,决定下一个要被处理的URL是什么。

l         ToePool:它表示一个线程池,管理了所有该抓取任务所创建的子线程。

l         ServerCache:它表示一个缓冲池,保存了所有在当前任务中,抓取过的Host名称和Server名称。

1)               如何获得CrawlController实例,并通过自主编程来使用Heritrix提供的API进行一次抓取任务?

    CrawlController提供了一个无参的构造函数:

public CrawlController()

注意:在构造一个实例并进行抓取任务时,需完成以下几个步骤:

(1)       首先构造一个XMLSettingsHandler对象,将order.xml内的属性信息装入,并调用它的initialize方法进行初始化。

(2)       调用CrawlController构造函数,构造一个CrawlController实例

(3)       调用CrawlControllerinitilizeSettingsHandler)方法,初始化CrawlController实例。其中,传入的参数就是在第一步里构造的XMLSettingsHandler实例。

(4)       当上述3步完成后,CrawlController就具备了运行的条件。此时,只需调用它的requestCrawlStart()方法,就可以启动线程池和Frontier,然后开始不断的抓取网页。

1)其中在CrawlControllerinitilizeSettingsHandler)方法整个代码如下:

public void initialize(SettingsHandler sH)

    throws InitializationException {

        sendCrawlStateChangeEvent(PREPARING, CrawlJob.STATUS_PREPARING);

 

        this.singleThreadLock = new ReentrantLock();

 

        this.settingsHandler = sH;

        this.order = settingsHandler.getOrder();

        this.order.setController(this);

        this.bigmaps = new Hashtable<String,CachedBdbMap<?,?>>();

        sExit = "";

        this.manifest = new StringBuffer();

        String onFailMessage = "";

        try {

            onFailMessage = "You must set the User-Agent and From HTTP" +

            " header values to acceptable strings. /n" +

            " User-Agent: [software-name](+[info-url])[misc]/n" +

            " From: [email-address]/n";

            order.checkUserAgentAndFrom();

 

            onFailMessage = "Unable to setup disk";

            if (disk == null) {

                setupDisk();

            }

 

            onFailMessage = "Unable to create log file(s)";

            setupLogs();

   

            onFailMessage = "Unable to test/run checkpoint recover";

            this.checkpointRecover = getCheckpointRecover();

            if (this.checkpointRecover == null) {

                this.checkpointer =

                    new Checkpointer(this, this.checkpointsDisk);

            } else {

                setupCheckpointRecover();

            }

           

            onFailMessage = "Unable to setup bdb environment.";

            setupBdb();

           

            onFailMessage = "Unable to setup statistics";

            setupStatTracking();

           

            onFailMessage = "Unable to setup crawl modules";

            setupCrawlModules();

        } catch (Exception e) {

            String tmp = "On crawl: "

                + settingsHandler.getSettingsObject(null).getName() + " " +

                onFailMessage;

            LOGGER.log(Level.SEVERE, tmp, e);

            throw new InitializationException(tmp, e);

        }

        Lookup.getDefaultCache(DClass.IN).setMaxEntries(1);

        

        setupToePool();

        setThresholds();

       

        reserveMemory = new LinkedList<char[]>();

        for(int i = 1; i < RESERVE_BLOCKS; i++) {

            reserveMemory.add(new char[RESERVE_BLOCK_SIZE]);

        }

    }

主要完成了以下操作:

(1)       XMLSettingsHandler中取出order

     this.settingsHandler = sH;

this.order = settingsHandler.getOrder();

(2)       检查用户设定的UserAgent等信息是否符合格式

order.checkUserAgentAndFrom();

(3)       设定开始抓取后保存文件信息的目录结构

if (disk == null) {

                setupDisk();

            }

(4)       初始化日志信息的记录工具

setupLogs();

(5)       初始化使用Berkley DB 的一些工具

setupBdb();

(6)       初始化ScopeFrontier以及ProcessorChain

setupCrawlModules();

(7)       最后实例化线程池

setupToePool();

在正常情况下,以上顺序不能随意变动,因为后一项功能的初始化很有可能需要前几项功能初始化的结果。例如线程池的初始化,必须要在先有了Frontier实例的基础上才可进行。

2)启动抓取工作的方法requestCrawlStart

代码如下:

/**

     * Operator requested crawl begin

     */

public void requestCrawlStart() {

//初始化处理器链

        runProcessorInitialTasks();

    //设置抓取状态的改变,以便能够激发一些Listeners来处理相应的事件

        sendCrawlStateChangeEvent(STARTED, CrawlJob.STATUS_PENDING);

        String jobState;

        state = RUNNING;

        jobState = CrawlJob.STATUS_RUNNING;

        sendCrawlStateChangeEvent(this.state, jobState);

 

        // A proper exit will change this value.

        this.sExit = CrawlJob.STATUS_FINISHED_ABNORMAL;

        //开始日志线程

        Thread statLogger = new Thread(statistics);

        statLogger.setName("StatLogger");

        statLogger.start();

        //启动Frontier,抓取工作开始

        frontier.start();

    }

heritrix中默认采用的FrontierBdbFrontier,其父类AbstractFroniter中的start()方法:

public void start() {

        if (((Boolean)getUncheckedAttribute(null, ATTR_PAUSE_AT_START))

                .booleanValue()) {

            // 若配置文件中不允许该次抓取开始则停止

            controller.requestCrawlPause();

        } else {

            // 若允许开始,则开始

            unpause();

        }

    }

 

//其中的unpause()方法

   synchronized public void unpause() {

        //去除当前阻塞变量

        shouldPause = false;

       //唤醒所有阻塞线程,开始抓取任务

        notifyAll();

    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值