Spider类的实现

 Spider类的实现:

网络机器人最最最核心的一个类终于姗姗来迟,不过没关系,最好的往往在高潮部分。

言归正传,Spider类包含了很多的接口所定义的方法,可以通过他们来命令Spider。Spider有三个重要的任务:1,它担当模拟接口,供使用Spider提供方法;2,与SpiderWorker进行通信;3,检测Spider何时完成。

详细代码清单:

  1. /**
  2.  * The Spider class is the main organizational(组织的) class for
  3.  * spidering.  It delegates work to the SpiderWorker class.
  4.  */
  5. package com.heaton.bot;
  6. import java.lang.reflect.Constructor;
  7. import java.lang.reflect.InvocationTargetException;
  8. public class Spider extends Thread implements ISpiderReportable 
  9. {
  10.   protected IWorkloadStorable workload;
  11.   protected SpiderWorker pool[];
  12.   protected boolean worldSpider;
  13.   protected ISpiderReportable manager;
  14.   protected boolean halted = false;
  15.   protected SpiderDone done = new SpiderDone();
  16.   protected int maxBodySize;
  17.   /**
  18.    * This constructor prepares the spider to begin.
  19.    * Basic information required to begin is passed.
  20.    * This constructor uses the internal workload manager(内存管理器).
  21.    *
  22.    * If you do not need a custom spider worker or 
  23.    * workload management, this is the constructor to use.
  24.    *
  25.    * @param manager The object that this spider reports its findings to.
  26.    * @param url The URL that the spider should begin at.
  27.    * @param http The HTTP handler used by this spider.
  28.    * @param poolsize The size of the thread pool.
  29.    */
  30.   public Spider(ISpiderReportable manager,String url,HTTP http,int poolSize)
  31.   {
  32.     this(manager,url,http,poolSize,new SpiderInternalWorkload());
  33.   }
  34.   /**
  35.    * This constructor prepares the spider to begin.
  36.    * Basic information required to begin is passed.
  37.    * This constructor allows the user to specify(指定) a
  38.    * customized(定制的) workload manager.
  39.    *
  40.    * @param manager The object that this spider reports its findings to.
  41.    * @param url The URL that the spider should begin at.
  42.    * @param http The HTTP handler used by this spider.
  43.    * @param poolsize The size of the thread pool.
  44.    * @param w A customized workload manager.
  45.    */
  46.   public Spider(ISpiderReportable manager,String url,HTTP http,int poolSize,IWorkloadStorable w)
  47.   {
  48.       try
  49.       {
  50.         init(manager,url,http.getClass(),SpiderWorker.class,poolSize,w);
  51.       }
  52.       // mostly ignore the exceptions since we're using the standard SpiderWorker stuff
  53.       catch(InstantiationException e)
  54.       {
  55.           Log.logException("Spider reflection exception",e);
  56.       }
  57.       catch(NoSuchMethodException e)
  58.       {
  59.           Log.logException("Spider reflection exception",e);
  60.       }      
  61.       catch(IllegalAccessException e)
  62.       {
  63.           Log.logException("Spider reflection exception",e);
  64.       }      
  65.       catch(InvocationTargetException e)
  66.       {
  67.           Log.logException("Spider reflection exception",e);
  68.       }      
  69.       
  70.   }
  71.   
  72.   /**
  73.    * This constructor prepares the spider to begin.
  74.    * Basic information required to begin is passed.
  75.    * This constructor allows the user to specify a
  76.    * customized workload manager.
  77.    *
  78.    * This constructor was added to allow you to specify
  79.    * a custom SpiderWorker class. Though not usually necessary
  80.    * this will allow you exact control over the HTML parse.
  81.    *
  82.    * @param manager The object that this spider reports its findings to.
  83.    * @param url The URL that the spider should begin at.
  84.    * @param http The HTTP handler used by this spider.
  85.    * @param worker A SpiderWorker class to be used to process the pages.
  86.    * @param poolsize The size of the thread pool.
  87.    * @param w A customized workload manager.
  88.    */
  89.   private Spider(ISpiderReportable manager,String url,Class http,Class worker,int poolSize,IWorkloadStorable w)  
  90.   throws InstantiationException,NoSuchMethodException,IllegalAccessException,InvocationTargetException  
  91.   {
  92.       init(manager,url,http,worker,poolSize,w);
  93.   }
  94.   
  95.   
  96.   /**
  97.    * Internal method that is called by the various constructors to setup the spider.
  98.    *
  99.    * @param manager The object that this spider reports its findings to.
  100.    * @param url The URL that the spider should begin at.
  101.    * @param http The HTTP handler used by this spider.
  102.    * @param http The spider worker
  103.    * @param poolsize The size of the thread pool.
  104.    * @param w A customized workload manager.
  105.    */
  106.   private void init(ISpiderReportable manager,String url,Class http,Class worker,int poolSize,IWorkloadStorable w)  
  107.   throws InstantiationException,NoSuchMethodException,IllegalAccessException,InvocationTargetException  
  108.   {
  109.     this.manager = manager;
  110.     worldSpider = false;
  111.     
  112.     Class types[] = { Spider.class,HTTP.class };
  113.     /*
  114.      * Constructor provides information about, and access to, 
  115.      * a single constructor for a class. 
  116.        Constructor permits widening conversions to occur when 
  117.        matching the actual parameters to newInstance() with 
  118.        the underlying(根本的) constructor's formal parameters, but 
  119.        throws an IllegalArgumentException if a narrowing 
  120.        conversion would occur.
  121.      */
  122.     Constructor constructor = worker.getConstructor(types);
  123.     
  124.     pool = new SpiderWorker[poolSize];
  125.     for ( int i=0;i<pool.length;i++ ) {
  126.       HTTP hc = (HTTP)http.newInstance();
  127.       Object params[]={this,hc};
  128.       
  129.       pool[i] = (SpiderWorker)constructor.newInstance(params);
  130.     }
  131.     workload = w;
  132.     if ( url.length()>0 ) {
  133.       workload.clear();
  134.       addWorkload(url);
  135.     }
  136.   }
  137.     
  138.     
  139.   /**
  140.    * Get the SpiderDone object used by this spider
  141.    * to determine when it is done.
  142.    *
  143.    * @return Returns true if the spider is done.
  144.    */
  145.   public SpiderDone getSpiderDone()
  146.   {
  147.     return done;
  148.   }
  149.   /**
  150.    * The main loop of the spider. This can be called
  151.    * directly, or the start method can be called to
  152.    * run as a background thread. This method will not
  153.    * return until there is no work remaining for the
  154.    * spider.
  155.    */
  156.   public void run()
  157.   {
  158.     if ( halted )
  159.       return;
  160.     /*
  161.      * 多线程开始执行。
  162.      */
  163.     for ( int i=0;i<pool.length;i++ )
  164.       pool[i].start();
  165.     try {
  166.       done.waitBegin();
  167.       done.waitDone();
  168.       Log.log(Log.LOG_LEVEL_NORMAL,"Spider has no work.");
  169.       spiderComplete();
  170.       for ( int i=0;i<pool.length;i++ ) {
  171.           /*
  172.            * 线程中断。
  173.            */
  174.         pool[i].interrupt();
  175.         /*
  176.          * Waits for this thread to die. 
  177.          */
  178.         pool[i].join();
  179.         pool[i] = null;
  180.       }
  181.     } catch ( Exception e ) {
  182.       Log.logException("Exception while starting spider", e);
  183.     }
  184.   }
  185.   /**
  186.    * This method is called to get a workload
  187.    * from the workload manager(作业管理器). If no workload
  188.    * is available, this method will block until
  189.    * there is one.
  190.    *
  191.    * @return Returns the next URL to be spidered.
  192.    */
  193.   synchronized public String getWorkload()
  194.   {
  195.     try {
  196.       for ( ;; ) {
  197.         if ( halted )
  198.           return null;
  199.         /*
  200.          * workload表面上看是IWorkloadStoreable接口的对象,
  201.          * 其实嘛,应该真正作SpiderInternalWorkload的对象
  202.          * 使用。
  203.          */
  204.         String w = workload.assignWorkload();
  205.         if ( w!=null )
  206.           return w;
  207.         wait();
  208.       }
  209.     } catch ( java.lang.InterruptedException e ) {
  210.     }
  211.     return null;
  212.   }
  213.   /**
  214.    * Called to add a workload to the workload manager.
  215.    * This method will release(释放) a thread that was waiting
  216.    * for a workload. This method will do nothing if the
  217.    * spider has been halted.
  218.    *
  219.    * @param url The URL to be added to the workload.
  220.    */
  221.   synchronized public void addWorkload(String url)
  222.   {
  223.     if ( halted )
  224.       return;
  225.     workload.addWorkload(url);
  226.     notify();
  227.   }
  228.   /**
  229.    * Called to specify(指定) this spider as either a world
  230.    * or site spider. See getWorldSpider for more information
  231.    * about what a world spider is.
  232.    *
  233.    * @param b True to be a world spider.
  234.    */
  235.   public void setWorldSpider(boolean b)
  236.   {
  237.     worldSpider = b;
  238.   }
  239.   /**
  240.    * Returns true if this is a world spider, a world
  241.    * spider does not restrict itself to a single site
  242.    * and will likely go on "forever".
  243.    *
  244.    * @return Returns true if the spider is done.
  245.    */
  246.   public boolean getWorldSpider()
  247.   {
  248.     return worldSpider;
  249.   }
  250.   /**
  251.    * Called when the spider finds an internal
  252.    * link. An internal link shares the same
  253.    * host address as the URL that started
  254.    * the spider. This method hands the link off
  255.    * to the manager and adds the URL to the workload
  256.    * if necessary.
  257.    *
  258.    * @param url The URL that was found by the spider.
  259.    * @return true - The spider should add this URL to the workload.
  260.    * false - The spider should not add this URL to the workload.
  261.    */
  262.   synchronized public boolean foundInternalLink(String url)
  263.   {
  264.     if ( manager.foundInternalLink(url) )
  265.       addWorkload(url);
  266.     return true;
  267.   }
  268.   /**
  269.    * Called when the spider finds an external
  270.    * link. An external link does not share the
  271.    * same host address as the URL that started
  272.    * the spider. This method hands the link off
  273.    * to the manager and adds the URL to the workload
  274.    * if necessary. If this is a world spider, then
  275.    * external links are treated as internal links.
  276.    *
  277.    * @param url The URL that was found by the spider.
  278.    * @return true - The spider should add this URL to the workload.
  279.    * false - The spider should not add this URL to the workload.
  280.    */
  281.   synchronized public boolean foundExternalLink(String url)
  282.   {
  283.       /*
  284.        * 为什么是环球蜘蛛的话,把它视为内部链接。
  285.        */
  286.     if ( worldSpider ) {
  287.       foundInternalLink(url);
  288.       return true;
  289.     }
  290.     if ( manager.foundExternalLink(url) )
  291.       addWorkload(url);
  292.     return true;
  293.   }
  294.   /**
  295.    * Called when the spider finds a type of
  296.    * link that does not point to another HTML
  297.    * page(for example a mailto link(邮件链接)). This method
  298.    * hands the link off to the manager and adds
  299.    * the URL to the workload if necessary.
  300.    *
  301.    * @param url The URL that was found by the spider.
  302.    * @return true - The spider should add this URL to the workload.
  303.    * false - The spider should not add this URL to the workload.
  304.    */
  305.   synchronized public boolean foundOtherLink(String url)
  306.   {
  307.     if ( manager.foundOtherLink(url) )
  308.       addWorkload(url);
  309.     return true;
  310.   }
  311.   /**
  312.    * Called to actually process a page. This is where the
  313.    * work actually done by the spider is usually preformed.
  314.    * 
  315.    * 处理网页这个方法,一般在实际的开发中具体描述使用。这里只是标明有这个
  316.    * 方法。
  317.    * 
  318.    * @param page The page contents.
  319.    * @param error true - This page resulted in an HTTP error.
  320.    * false - This page downloaded correctly.
  321.    */
  322.   synchronized public void processPage(HTTP page)
  323.   {
  324.     manager.processPage(page);
  325.   }
  326.   /**
  327.    * This method is called by the spider to determine if
  328.    * query strings should be removed. By default the spider
  329.    * always chooses to remove query strings, so true is
  330.    * returned.
  331.    *
  332.    * @return true - Query string should be removed.
  333.    * false - Leave query strings as is.
  334.    */
  335.   synchronized public boolean getRemoveQuery()
  336.   {
  337.     return true;
  338.   }
  339.   /**
  340.    * Called to request that a page be processed.
  341.    * This page was just downloaded by the spider.
  342.    * This messages passes this call on to its
  343.    * manager.
  344.    *
  345.    * @param page The page contents.
  346.    * @param error true - This page resulted in an HTTP error.
  347.    * false - This page downloaded correctly.
  348.    */
  349.   synchronized public void completePage(HTTP page,boolean error)
  350.   {
  351.     workload.completeWorkload(page.getURL(),error);
  352.     // if this was a redirect, then also complete the root page
  353.     if ( page.getURL().equals(page.getRootURL()) )
  354.       workload.completeWorkload(page.getRootURL(),error);
  355.   }
  356.   /**
  357.    * Called when the spider has no more work. This method
  358.    * just passes this event on to its manager.
  359.    */
  360.   synchronized public void spiderComplete()
  361.   {
  362.     manager.spiderComplete();
  363.   }
  364.   /**
  365.    * Called to cause the spider to halt. The spider will not halt
  366.    * immediately. Once the spider is halted the run method will
  367.    * return.
  368.    */
  369.   synchronized public void halt()
  370.   {
  371.     halted = true;
  372.     workload.clear();
  373.     notifyAll();
  374.   }
  375.   /**
  376.    * Determines if the spider has been halted.
  377.    *
  378.    * @return Returns true if the spider has been halted.
  379.    */
  380.   public boolean isHalted()
  381.   {
  382.     return halted;
  383.   }
  384.   /**
  385.    * This method will set the maximum body size
  386.    * that will be downloaded.
  387.    *
  388.    * @param i The maximum body size, or -1 for unlifted.
  389.    */
  390.   public void setMaxBody(int mx)
  391.   {
  392.     maxBodySize = mx;
  393.     for ( int i=0;i<pool.length;i++ )
  394.       pool[i].getHTTP().setMaxBody(mx);
  395.   }
  396.   /**
  397.    * This method will return the maximum body size
  398.    * that will be downloaded.
  399.    *
  400.    * @return The maximum body size, or -1 for unlifted.
  401.    */
  402.   public int getMaxBody()
  403.   {
  404.     return maxBodySize;
  405.   }
  406. }

Spider类为SpiderWorker对象提供的主要任务是管理作业。作业Spider目前访问的URL的列表。

Spider类还必须检测Spider何时完成,这一任务由SpiderDone类完成。SpiderDone对象可被每个SpiderWorker使用。SpiderDone对象跟踪SpiderWorker对象并检测Spider何时完成。

That's OK!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值