我的家園

          我的家園

          Nutch 源代碼分析(1) Crawl 類

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

            Crawl 類是運(yùn)行抓取程序的入口,代碼不多,但關(guān)聯(lián)的其他類不少。
            抓取的流程是:

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

            2. 從crawldb中生成一個(gè)url的子集用于抓取
            3. 抓取網(wǎng)頁(yè)
            4. 分析網(wǎng)頁(yè)
            5. 更新 crawlDb ,增加新抓取的 url

            6. 循環(huán)執(zhí)行 2-5 步,直到達(dá)到指定的抓取深度

            之后,還需要進(jìn)行鏈接反轉(zhuǎn),將索引導(dǎo)入到 solr 等。

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

            Configured 和 Tool 是 hadoop 中的概念
            Configured 是 hadoop 中用來(lái)提供配置信息的,在 ToolRunner.run 方法中,會(huì)將創(chuàng)建好的 Configuration 對(duì)象通過(guò) Configured.setConf 方法注入到 Crawl 中。
            Tool 是 hadoop 中用來(lái)處理命令行參數(shù)并修改 Map-Reduce 任務(wù)的參數(shù),它需要在 run 方法中處理這些命令行參數(shù)。

            因?yàn)?Crawl 實(shí)現(xiàn)了 Tool 接口,我們可以通過(guò)命令行啟動(dòng)數(shù)據(jù)抓取的 Map-Reduce 任務(wù)。
            啟動(dòng) Crawl 的 main 方法如下:
            public static void main(String args[]) throws Exception {
              // 創(chuàng)建 Configuration  對(duì)象
              Configuration conf = NutchConfiguration.create();
          
              // 執(zhí)行任務(wù)
              int res = ToolRunner.run(conf, new Crawl(), args);
          
              // 退出程序
              System.exit(res);
            }
          

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

            首先是參數(shù)的設(shè)置:
              // 默認(rèn)參數(shù)
              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;
          

            這幾個(gè)參數(shù)的含義如下:

            rootUrlDir : 要抓取的起始 url 所在的目錄
            dir : 默認(rèn)情況下,抓取時(shí)生成的文件的目錄
            threads : 抓取數(shù)據(jù)的線程數(shù)
            depth : 通過(guò)外鏈抓取網(wǎng)頁(yè)的深度,從起始 url 算起
            topN : 每輪抓取獲得的新的 url 中,只對(duì)分值最高的 topN 個(gè) url 再次抓取
            solrUrl : solr 的地址。用于調(diào)用 solr 的 api 建立用于搜索的索引。


            這些參數(shù)是可以根據(jù)命令行的輸入修改的:
              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]);
                }
              }
          


            然后需要?jiǎng)?chuàng)建抓取程序?qū)⒁玫降膶?duì)象:
              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());
          

            這里簡(jiǎn)要說(shuō)明一下這些對(duì)象的作用:
            injector : 將初始的 URL 地址到 crawlDb
            generator : 生成要抓取的 URL
            fetcher : 抓取網(wǎng)頁(yè)
            parseSegment : 分析網(wǎng)頁(yè)
            crawlDbTool : CrawlDb 類的實(shí)例,存放將要抓取的 URL
            linkDbTool : 用于存放鏈接之間的引用關(guān)系,便于計(jì)算權(quán)重


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

            前面通過(guò)抓取和分析網(wǎng)頁(yè)得到的鏈接格式為 源鏈接 => 目標(biāo)鏈接,
            需要通過(guò)反轉(zhuǎn),得到目標(biāo)鏈接對(duì)應(yīng)的源鏈接,以便于計(jì)算目標(biāo)鏈接的權(quán)重等:
            linkDbTool.invert(linkDb, segments, true, true, false);
          

            最后,如果指定了 solrUrl,需要將 nutch 索引導(dǎo)入到 solr 中
                // 將索引導(dǎo)入到 solr
                if (solrUrl != null) {
          
                  // 獲取創(chuàng)建好的 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);
                }
          


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




          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 广宁县| 兴业县| 东明县| 丹巴县| 马尔康县| 九江市| 阿城市| 海丰县| 凤山市| 余江县| 安龙县| 礼泉县| 西贡区| 临海市| 新邵县| 开封市| 黑河市| 南通市| 抚远县| 宜兰县| 深水埗区| 苍梧县| 富阳市| 临汾市| 聂拉木县| 河曲县| 泽库县| 武穴市| 平定县| 汉阴县| 南乐县| 乐东| 阳东县| 本溪| 嘉鱼县| 石门县| 伊宁市| 玉环县| 绥化市| 阿尔山市| 穆棱市|