我的家園

          我的家園

          Nutch 源代碼分析(1) Crawl 類

          Posted on 2012-04-15 16:27 zljpp 閱讀(322) 評論(0)  編輯  收藏
            (以下分析針對的是 nutch 1.4)

            Crawl 類是運行抓取程序的入口,代碼不多,但關聯的其他類不少。
            抓取的流程是:

            1. 將初始的 URL 地址注入到 crawlDb

            2. 從crawldb中生成一個url的子集用于抓取
            3. 抓取網頁
            4. 分析網頁
            5. 更新 crawlDb ,增加新抓取的 url

            6. 循環執行 2-5 步,直到達到指定的抓取深度

            之后,還需要進行鏈接反轉,將索引導入到 solr 等。

            Crawl 類的聲明如下:
          public class Crawl extends Configured implements Tool
          

            Configured 和 Tool 是 hadoop 中的概念
            Configured 是 hadoop 中用來提供配置信息的,在 ToolRunner.run 方法中,會將創建好的 Configuration 對象通過 Configured.setConf 方法注入到 Crawl 中。
            Tool 是 hadoop 中用來處理命令行參數并修改 Map-Reduce 任務的參數,它需要在 run 方法中處理這些命令行參數。

            因為 Crawl 實現了 Tool 接口,我們可以通過命令行啟動數據抓取的 Map-Reduce 任務。
            啟動 Crawl 的 main 方法如下:
            public static void main(String args[]) throws Exception {
              // 創建 Configuration  對象
              Configuration conf = NutchConfiguration.create();
          
              // 執行任務
              int res = ToolRunner.run(conf, new Crawl(), args);
          
              // 退出程序
              System.exit(res);
            }
          

            NutchConfiguration.create 會加載 nutch-default.xml 和 nutch-site.xml 中的配置信息生成 Configuration  對象。
            ToolRunner.run 方法會將創建好的 Configuration 對象通過 Configured.setConf 方法注入到 Crawl 中(Crawl 繼承了Configured),并將參數的處理委托給 Tool.run 方法(Crawl 實現了 Tool 接口,因此需要提供 run 方法的實現)。
            接下來我們重點分析一下 Crawl 類的 run 方法。

            首先是參數的設置:
              // 默認參數
              Path rootUrlDir = null;
              Path dir = new Path("crawl-" + getDate());
              int threads = getConf().getInt("fetcher.threads.fetch", 10);
              int depth = 5;
              long topN = Long.MAX_VALUE;
              String solrUrl = null;
          

            這幾個參數的含義如下:

            rootUrlDir : 要抓取的起始 url 所在的目錄
            dir : 默認情況下,抓取時生成的文件的目錄
            threads : 抓取數據的線程數
            depth : 通過外鏈抓取網頁的深度,從起始 url 算起
            topN : 每輪抓取獲得的新的 url 中,只對分值最高的 topN 個 url 再次抓取
            solrUrl : solr 的地址。用于調用 solr 的 api 建立用于搜索的索引。


            這些參數是可以根據命令行的輸入修改的:
              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 ("-solr".equals(args[i])) {
                  solrUrl = StringUtils.lowerCase(args[i + 1]);
                  i++;
                } else if (args[i] != null) {
                  rootUrlDir = new Path(args[i]);
                }
              }
          


            然后需要創建抓取程序將要用到的對象:
              Path tmpDir = job.getLocalPath("crawl"+Path.SEPARATOR+getDate());
              Injector injector = new Injector(getConf());
              Generator generator = new Generator(getConf());
              Fetcher fetcher = new Fetcher(getConf());
              ParseSegment parseSegment = new ParseSegment(getConf());
              CrawlDb crawlDbTool = new CrawlDb(getConf());
              LinkDb linkDbTool = new LinkDb(getConf());
          

            這里簡要說明一下這些對象的作用:
            injector : 將初始的 URL 地址到 crawlDb
            generator : 生成要抓取的 URL
            fetcher : 抓取網頁
            parseSegment : 分析網頁
            crawlDbTool : CrawlDb 類的實例,存放將要抓取的 URL
            linkDbTool : 用于存放鏈接之間的引用關系,便于計算權重


            完成以上的準備工作之后,就開始執行主要的處理邏輯:
              // 初始化 crawlDb
              // 將初始的 URL 地址到 crawlDb 
              injector.inject(crawlDb, rootUrlDir);
          
              int i;
          
              // 循環執行,直到達到指定的抓取深度
              for (i = 0; i < depth; i++) {
                // 生成要抓取的 URL 
                Path[] segs = generator.generate(crawlDb, segments, -1, topN, System.currentTimeMillis());
          
                // 沒有需要抓取的 URL 了,提前中止抓取過程
                if (segs == null) {
                  LOG.info("Stopping at depth=" + i + " - no more URLs to fetch.");
                  break;
                }
          
                fetcher.fetch(segs[0], threads);  // 抓取網頁
          
                if (!Fetcher.isParsing(job)) {
                  parseSegment.parse(segs[0]);    // 分析網頁
                }
                crawlDbTool.update(crawlDb, segs, true, true); // 更新 crawldb,增加需要抓取的 URL
              }
          

            前面通過抓取和分析網頁得到的鏈接格式為 源鏈接 => 目標鏈接,
            需要通過反轉,得到目標鏈接對應的源鏈接,以便于計算目標鏈接的權重等:
            linkDbTool.invert(linkDb, segments, true, true, false);
          

            最后,如果指定了 solrUrl,需要將 nutch 索引導入到 solr 中
                // 將索引導入到 solr
                if (solrUrl != null) {
          
                  // 獲取創建好的 nutch 索引的文件索引
                  FileStatus[] fstats = fs.listStatus(segments, HadoopFSUtil.getPassDirectoriesFilter(fs));
          
                  // 建立 Solr 索引
                  SolrIndexer indexer = new SolrIndexer(getConf());
                  indexer.indexSolr(solrUrl, crawlDb, linkDb,  Arrays.asList(HadoopFSUtil.getPaths(fstats)));
          
                  // 去重
                  SolrDeleteDuplicates dedup = new SolrDeleteDuplicates();
                  dedup.setConf(getConf());
                  dedup.dedup(solrUrl);
                }
          


            以上只是對源代碼進行字面上的分析,更深入的分析可以參考以下文章:
            http://blog.csdn.net/kauu/article/details/1823830
            http://www.diybl.com/course/3_program/java/javajs/20100719/459450.html




          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 镶黄旗| 高雄市| 南澳县| 北票市| 麻城市| 师宗县| 蒲江县| 鹤山市| 兰考县| 岚皋县| 余江县| 五常市| 五峰| 盘山县| 津市市| 安多县| 都兰县| 瑞安市| 丰城市| 桦川县| 四平市| 崇义县| 兴化市| 深泽县| 阿拉善左旗| 南溪县| 临沧市| 巴塘县| 彰武县| 皋兰县| 信阳市| 株洲县| 乌拉特中旗| 滁州市| 山阳县| 固阳县| 文昌市| 桐梓县| 万荣县| 辰溪县| 定西市|