Nutch Crawler工作流程及文件格式詳細分析

Crawler和Searcher兩部分被盡是分開,其主要目的是爲了使兩個部分可以布地配置在硬件平臺上,例如Crawler和Searcher分別被放置在兩個主機上,這樣可以極大的提高靈活性和性能。
一、總體介紹:

1、先注入種子urls到crawldb
2、循環:

    * generate 從crawldb中生成一個url的子集用於抓取
    * fetch 抓取上一小的url生成一個個segment
    * parse 分析已抓取segment的內容
    * update 把已抓取的數據更新到原先的crawldb

3、從已抓取的segments中分析出link地圖
4、索引segment文本及inlink錨文本
二、相關的數據結構:
Crawl DB
● CrawlDb 是一個包含如下結構數據的文件:
<URL, CrawlDatum>
● CrawlDatum:
<status, date, interval, failures, linkCount, ...>
● Status:
{db_unfetched, db_fetched, db_gone,linked,
fetch_success, fetch_fail, fetch_gone}

  爬蟲Crawler:
Crawler 的工作流程包括了整個nutch的所有步驟--injector,generator,fetcher,parseSegment, updateCrawleDB,Invert links, Index ,DeleteDuplicates, IndexMerger
Crawler涉及的數據文件和格式和含義,和以上的各個步驟相關的文件分別被存放在物理設備上的以下幾個文件夾裏,crawldb,segments,indexes,linkdb,index五個文件夾裏。
那麼各個步驟和流程是怎麼,各個文件夾裏又是放着什麼呢?
觀察Crawler類可以知道它的流程
./nutch crawl urls -dir ~/crawl -depth 4 -threads 10 -topN 2000

1、Injector injector = new Injector(conf);

Usage: Injector <crawldb> <url_dir>
首先是建立起始url集,每個url都經過URLNormalizers、filter和scoreFilter三個過程並標記狀態。首先經過normalizer plugin,把url進行標準化,比如basic nomalizer的作用有把大寫的url標準化爲小寫,把空格去除等等。然後再經過的plugin 是filter,可以根據你寫的正則表達式把想要的url留下來。經過兩個步驟後,然後就是把這個url進行狀態標記,每個url都對應着一個 CrawlDatum,這個類對應着每個url在所有生命週期內的一切狀態。細節上還有這個url處理的時間和初始時的分值。
  同時,在這個步驟裏,會在文件系統裏生成 如下文件 crawlDB\current\part-00000
  這個文件夾裏還有.data.crc , .index.crc, data, index四個文件

● MapReduce1: 把輸入的文件轉換成DB格式
In: 包含urls的文本文件
Map(line) → <url, CrawlDatum>; status=db_unfetched
Reduce() is identity;
Output: 臨時的輸出文件夾
● MapReduce2: 合併到現有的DB
Input: 第一步的輸出和已存在的DB文件
Map() is identity.
Reduce: 合併CrawlDatum成一個實體(entry)
Out: 一個新的DB
  

2、Generator generator = new Generator(conf);
//Generates a subset of a crawl db to fetch

Usage: Generator <crawldb> <segments_dir> [-force] [-topN N] [-numFetchers numFetchers] [-adddays numDays] [-noFilter]
在這個步驟裏,Generator一共做了四件事情,
1、給前面injector完成的輸出結果裏按分值選出前topN個url,作爲一個fetch的子集。
2、根據第一步的結果檢查是否已經選取出一些url,CrawlDatum的實體集。
3、再次轉化,此次要以url的host來分組,並以url的hash來排序。
4、根據以上的步驟的結果來更新crawldb(injector產生)。

● MapReduce1: 根據要求選取一些要抓取的url
In: Crawl DB 文件
Map() → if date≥now, invert to <CrawlDatum, url>
Partition 以隨機的hash值來分組
Reduce:
compare() 以 CrawlDatum.linkCount的降序排列
output only top-N most-linked entries
● MapReduce2: 爲下一步抓取準備
Map() is invert; Partition() by host, Reduce() is identity.
Out: 包含<url,CrawlDatum> 要並行抓取的文件



  3、Fetcher fetcher = new Fetcher(conf);
//The fetcher. Most of the work is done by plugins
Usage: Fetcher <segment> [-threads n] [-noParsing]
這個步驟裏,Fetcher所做的事情主要就是抓取了,同時也完成一些其它的工作。首先,這是一個多線程的步驟,默認以10個線程去抓取。根據抓取回來後的結果狀態來進行不同的標記,存儲,再處理等等行爲。輸入是上一步驟Generator產生的segment文件夾,這個步驟裏,考慮到先前已經按照ip 或host來patition了,所以在此就不再把input文件進行分割了。程序繼承了SequenceFileInputFormat重寫了 inputFormat來達到這點。這個類的各種形爲都是插件來具體完成的,它只是一個骨架一樣爲各種插件提供一個平臺。它先根據url來取出具體的 protocol,得到protocolOutput,進而得到狀態status及內容content。然後,根據抓取的狀態status來繼續再處理。再處理時,首先會將這次抓取的內容content、狀態status及它的狀態標記進行存儲。這個存儲的過程中,還會記下抓取的時間,再把segment 存過metadata,同時在分析parsing前經過scoreFilter,再用parseUtil(一系列的parse插件)進行分析,分析後再經過一次score插件的處理。經過這一系列處理後,最後進行輸出(url,fetcherOutput)。
之前講到根據抓取回來的各種狀態,進行再處理,這些狀態一共包括12種,比如當抓取成功時,會像上剛講的那樣先存儲結果,再判斷是否是鏈接跳轉,跳轉的次數等等處理。

● MapReduce:抓取
In: <url,CrawlDatum>, 以host分區, 以hash值排序
Map(url,CrawlDatum) → <url, FetcherOutput>
多線程的, 同步的map實現
調用已有的協議protocol插件
FetcherOutput: <CrawlDatum, Content>
Reduce is identity
Out: 兩個文件: <url,CrawlDatum>, <url,Content>


4、 ParseSegment parseSegment = new ParseSegment(conf);
//Parse content in a segment
Usage: ParseSegment segment
對於這個步驟的邏輯比較簡單,只是對抓取後上一步驟存儲在segment裏的content進行分析parse。同樣,這個步驟的具體工作也是由插件來完成的。

MapReduce: 分析內容
In: <url, Content> 抓取來的內容
Map(url, Content) → <url, Parse>
調用分析插件parser plugins
Reduce is identity.
Parse: <ParseText, ParseData>
Out: 分割成三個文件: <url,ParseText>, <url,ParseData> 和<url,CrawlDatum> 爲了outlinks.


5、CrawlDb crawlDbTool = new CrawlDb(conf);
//takes the output of the fetcher and updates the crawldb accordingly.
Usage: CrawlDb <crawldb> (-dir <segments> | <seg1> <seg2> ...) [-force] [-normalize] [-filter] [-noAdditions]
這個類主要是根據fetcher的輸出去更新crawldb。 map和reduce分別做了兩方面的事情,在map裏是對url的nomalizer,和filte,在reduce裏是對新抓取進來的頁面(CrawlDatum)和原先已經存在的進行合併。

MapReduce:合併抓取的和分析後的輸出到crawldb裏
In: <url,CrawlDatum>現有的db加上抓取後的和分析後的輸出
Map() is identity
Reduce() 合併所有實體(entry)成一個,以抓取後的狀態覆蓋原先的db狀態信息,統計出分析後的鏈接數
Out: 新的crawl db

6.LinkDb linkDbTool = new LinkDb(conf);
//Maintains an inverted link map, listing incoming links for each url.
Usage: LinkDb <linkdb> (-dir <segmentsDir> | <seg1> <seg2> ...) [-force] [-noNormalize] [-noFilter]
這個類的作用是管理新轉化進來的鏈接映射,並列出每個url的外部鏈接(incoming links)。先是對每一個url取出它的outLinks,作map操作把這個url作爲每個outLinks的incoming link,在reduce裏把根據每個key來把一個url的所有incoming link都加到inlinks裏。這樣就把每個url的外部鏈接統計出來了。然後一步是對這些新加進來的鏈接進行合併。

● MapReduce: 統計每個鏈接的外部鏈接
In: <url,ParseData>, 包含所有鏈接的分析後的結果
Map(srcUrl, ParseData> → <destUrl, Inlinks>
爲每個鏈出鏈接收集一個入鏈。
Inlinks: <srcUrl, anchorText>*
Reduce()加上外部入鏈數量
Out: <url, Inlinks>, 一個相關完整的鏈接地圖


7.Indexer indexer = new Indexer(conf);
//Create indexes for segments
Usage: <index> <crawldb> <linkdb> <segment> ...
  這個類的任務是另一方面的工作了,它是基於hadoop和lucene的分佈式索引。它就是爲前面爬蟲抓取回來的數據進行索引好讓用戶可以搜索到這些數據。這裏的輸入就比較多了,有segments下的fetch_dir,parseData和parseText,還有crawldb下的 current_dir和linkdb下的current_dir。在這個類裏,map也不做,在reduce時處理。當然要把這些數據體組合成一個 lucene的document讓它索引了。在reduce裏組裝好後收集時是<url,doc>,最後在輸出的OutputFormat類裏進行真正的索引。

● MapReduce: 生成lucene的索引文件
In: 外個文件, values 以 <Class, Object>包裝
<url, ParseData> from parse, 有title, metadata, 等等信息.
<url, ParseText> from parse, 文本 text
<url, Inlinks> from invert, 錨文本anchors
<url, CrawlDatum> from fetch,用於抓取
Map() is identity
Reduce() 生成Lucene Document
調用index插件
Out: 建立Lucene 索引; 最後存儲到文件系統上


8. DeleteDuplicates dedup = new DeleteDuplicates(conf);
//這個類的作用就是它的名字了。
Usage: DeleteDuplicates <indexes> ...
  這個類的作用就是這它的名字所寫的意思--去重。前面索引後(當然不是一次時的情況)會有重複,所以要去重。爲什麼呢,在一次索引時是不重複的,可是多次抓取後就會有重複了。就是這個原因纔要去重。當然去重的規則有兩種一個是以時間爲標準,一種是以內容的md5值爲標準。
9.IndexMerger merger = new IndexMerger(conf);
IndexMerger [-workingdir <workingdir>] outputIndex indexesDir...
  這個類就比較簡單了,把所有的小索引合併成一個索引。在這一步沒有用到map-reduce。

  在這九大步驟中generator,fetcher,parseSegment,crawlDbTool會根據抓取的層數循環運行,當抓取的層數大於1時會運行linkInvert,index,dedup,和merge。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章