NCrawler:.NET 的 CrawlerT
Codeplex 軟體套件(Package)資訊 | |
套件名稱 | NCrawler |
作者 | Developers: boomhauer Coordinators: EsbenCarlsen |
目前版本 | 2.0 Stable |
URL | http://ncrawler.codeplex.com/ |
使用難易度 | 中 |
使用此套件時可用的輔助工具 | 無 |
基礎知識 | 基本類別使用。 知曉 Regular Expression。 熟悉介面的使用。 |
偵測資訊:網路爬蟲 Crawler
搜尋引擎如 Google/Bing 或是 Yahoo 等等,廣納了全球數百萬(甚至數千萬)個網站的網址,以及以海量來計的網頁連結與內容,以作為廣大網路使用搜尋資料之用,廣告商也由此處獲得商機,在搜尋引擎的各個結果頁部份安插廣告以增加收益,不過你可知道搜尋引擎資料庫的這些網頁與網址資訊是如何來的嗎?答案就是數千甚至數萬個執行緒(thread)的網路爬蟲(Crawler)。
網路爬蟲是機器人(bot)的一種,它由搜尋引擎的網址資料庫取得根網址的資料(一般使用網站註冊時所輸入的資料,或由其他網址的相關連結取得)後,自身即開始產生數個(或數十個,由管理人員設定)執行緒,針對網址所包含的網頁(通常是首頁)中的各個連結開始偵測,連結可能是一個網頁,也可以是一個圖檔、文件、視訊、甚至於是 JavaScript 指令碼等等,下載到主程式中,主程式會再剖析內容以找出連結資料,然後再繼續往更深的層次鑽探,所有下載剖析得到的 URL 都會被送入一個佇列(Queue)中(不論是由哪支程式探得的),等待由前一個處理完的執行緒取得新的 URL 再進行處理,直到最後一個 URL 被處理完畢為止。最後將所得的資料儲存到資料庫中,以備搜尋引擎使用。
圖:標準的 Web Crawler 的內部高階架構(來源:維基百科)
NOTE
通常在公眾網站伺服器的記錄檔(例如 IIS 的 log 檔)中,或多或少都會看到一些 Bot 的來訪記錄,這些都是 Web Crawler 進入網站時留下的,多數 Crawler 都會註明來源(例如 GoogleBot),且通常只有在公眾網路會出現,如果私人網路上有出現,那可能表示防火牆有設定問題(因為私人網路通常不會讓 Bot 進來的,或是內部也有類似的軟體會使用 Crawler)。
不過除了搜尋引擎以外,企業搜尋(Enterprise Search)以及知識管理(KM)類型的系統,或多或少都會用到 Crawler 的能力,主要原因是這些系統都需要處理到大量的資料,而這些資料的來源都要依賴 Crawler 的能力,像是 Database Crawler 或是 Document Crawler 等等的工具,它們可以深入不同的資料來源去找出需要的資料在哪個位置,並且運用關鍵字或標記將它們的位置記錄下來後,使用者即可直接以關鍵字去搜尋結果集,然後取得要找的資料的位置(例如檔案內容包含某個關鍵字,或是資料記錄中有某個關鍵字等)。
NOTE
應用在企業網路以及政府網站的整站檢索(Entire Site Search)或全文檢索(Full-Text Search)的資料來源(資料庫)基本上就是應用 Crawler 的技術在做的,而且它們都是一個套裝軟體,例如 Openfind、龍捲風搜尋或是 Microsoft Search Server 等都有 Crawler 的影子。
NOTE
比起 Web Crawler,企業搜尋要用的技術比搜尋引擎要來的多,除了文字搜尋以外,圖像搜尋(Image Search)、光學辨識(OCR)以及文字探勘(Text Mining)等,都是企業搜尋軟體可能會用到的技術,其原因是企業資料的類型比搜尋引擎要多太多了(各類型的檔案與內容都不太一樣)。但近幾年,搜尋引擎也開始在使用這些技術,例如 Google 的圖片搜尋(http://images.google.com.tw/imghp?hl=zh-TW&tab=wi)。
另外,以網站內容為主的內容管理系統(Content Management System)也會應用到 Crawler,其主要功用的探知無效連結(Bad Links/Invalid Links/Failed Links),以先行反應可能的資源中斷問題。另一種應用則是偵測網頁的熱門程度(其他網頁中有使用到該網頁的程度),這可以被視為網站評量的其中一個指數。本文所要介紹的 NCrawler,就是可以快速開發 Web Crawler 的一個工具。
NCrawler 簡介
NCrawler 是一個 Web Crawler 工具,它可以讓開發人員很輕鬆的發展出具有 Web Crawler 能力的應用程式,並且具有可以延展的能力,讓開發人員可以擴充它的功能,以支援其他類型的資源(例如 PDF/Word/Excel 等檔案或其他資料來源)。NCrawler 使用多執行緒(Multi-threading)模式針對網路資源進行探索,並且會依照給定的步驟來處理抓取到的資源,然後依給定的資源來活動(像是寫入資料庫或是擷取部份資料等等)。
目前 NCrawler 支援的搜尋類型有:
- HTML 網頁(需要 HtmlAgilityPack.dll)。
- PDF 檔案(需要 iTextSharp PDF Library)。
而 NCrawler 支援的中介儲存區有:
- 記憶體(使用 NCrawler.Crawler 進行時)。
- 資料庫(使用 NCrawler.DbServices.Crawler 進行時)。
- 隔離儲存區(使用 NCrawler.IsolatedStorageServices.Crawler 進行時)。
NCrawler 的中介儲存區儲存了包含網址以及探索佇列等資料,以供應 NCrawler 引擎擷取網址以進行作業之用。並且保留歷史資料以備查詢。
例如,如果要搜尋某個網站的所有連結,可以使用下列的程式碼:
[C#]
- Crawler c = new Crawler("http://mysite.com.tw", new HtmlDocumentProcessor())
- {
- MaximumThreadCount = 5,
- MaximumCrawlDepth = 2
- };
-
- c.Crawl();
上列程式碼是不會輸出任何東西,因為輸出也是一個步驟(Step),如果要輸出的話,需要另外寫一個繼承自 IPipelineStep 介面的類別,處理它的 Process() 方法以輸出資料:
[C#]
- public class DumpResult : IPipelineStep
- {
- public void Process(Crawler crawler, PropertyBag propertyBag)
- {
- Console.WriteLine("Find URL:" + propertyBag.Step.Uri);
- }
- }
然後改寫上面的程式,將 DumpResult 類別加進去:
[C#]
- Crawler c = new Crawler("http://mysite.com.tw", new HtmlDocumentProcessor(), new DumpResult())
- {
- MaximumThreadCount = 5,
- MaximumCrawlDepth = 2
- };
-
- c.Crawl();
這樣就可以透過 DumpResult 類別取得所有被探知到的連結路徑。
使用方式
首先,先下載原始檔並解壓縮後,使用 Visual Studio 2008 開啟 NCrawler.sln 檔案,並選擇功能表的『建置/建置方案』,重新編譯所有程式,編譯完成後,就可以在各專案資料夾下的 bin\Debug(或 bin\Release,看是用哪種模式編譯)下找到元件的 DLL 檔案,在需要使用它的專案中引用它們的參考即可。若元件需要使用到其他的 DLL(如前面列表中所示),則必要的 DLL 可以在根目錄的 Repository 資料夾中找到。
Crawler 是 NCrawler 的主類別,啟動網路探索的機制要由它來做,它主控了下載資源回用戶端後的解析程序,以及管理啟動的執行緒,開發人員可以透過設定 MaximumThreadCount 的值來設定最大可同時啟動多少執行緒來處理;同時為了要控制探索的深度以避免無限迴圈探索(infinite loop discover)的問題,它提供了 MaximumCrawlDepth 屬性以設定最大的深度;它也可以設定要排除哪些資源,例如不針對圖檔進行內容探索或不抓取圖檔路徑時,能利用 DisAllowedUrls 屬性來排除不允許的 URL 集合。
[C#]
- Crawler c = new Crawler("http://ncrawler.codeplex.com/", new HtmlDocumentProcessor(), new DumperStep());
- c.MaximumThreadCount = 3;
- c.MaximumCrawlDepth = 2;
- c.BlackListedUriRegexMatchers = new [] { new Regex(@"(\.jpg|\.css|\.js|\.gif|\.jpeg|\.png)", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase) };
- c.Crawl();
NOTE
在 NCrawler 官方網站上的範例,屬性名稱是舊版的,在新版會找不到屬性,因此若需要範例,可以參考新版的 NCrawler.Demo 專案中的範例程式。
實務應用:無效連結偵測程式
NCrawler 具有強大的 URL 探索能力,以及多執行緒的處理能力,因此筆者使用它撰寫一支簡單的無效連結偵測程式(只要不是 HTTP 200 的回應都算無效),可以使用 Windows 排程來定時執行,並回報無效連結的偵測結果,列出無效連結的清單報表等。無效連結偵測程式由 InvalidLinkDetector 類別作為核心功能提供者,裡面包裝了 NCrawler 以及記錄用的 XML Document 物件,程式碼如下:
[C#]
- public class InvalidLinkDetector
- {
- private XmlDocument _writerDoc = null;
- private Crawler _crawler = null;
-
- public InvalidLinkDetector(string DetectUrl, int MaxThreadCount, int MaxCrawlDepth)
- {
- this._writerDoc = new XmlDocument();
- this._writerDoc.LoadXml(" ");
-
- this._crawler = new Crawler(DetectUrl, new HtmlDocumentProcessor(), new ScanResultWriter(this._writerDoc))
- {
- MaximumThreadCount = MaxThreadCount,
- MaximumCrawlDepth = MaxCrawlDepth
- };
-
- this._crawler.CrawlFinished += new EventHandler (CrawlFinished);
- this._crawler.PipelineException += new EventHandler (PipelineException);
- }
-
- public void Run()
- {
- this._crawler.Crawl();
- }
-
- private void PipelineException(object sender, NCrawler.Events.PipelineExceptionEventArgs e)
- {
- Console.WriteLine("Exception occurred in pipeline: {0}, message: {1}", e.PropertyBag.Step.GetType().Name, e.Exception.Message);
- }
-
- private void CrawlFinished(object sender, NCrawler.Events.CrawlFinishedEventArgs e)
- {
- this._writerDoc.Save(Environment.CurrentDirectory + @"\" + DateTime.Now.ToString("yyyyMMdd HHmmss") + ".xml");
- this._writerDoc = null;
- }
- }
-
- public class ScanResultWriter : IPipelineStep
- {
- private XmlDocument _writerDoc = null;
-
- public ScanResultWriter(XmlDocument doc)
- {
- this._writerDoc = doc;
- }
-
- public void Process(Crawler crawler, PropertyBag propertyBag)
- {
- if (propertyBag.StatusCode != HttpStatusCode.OK)
- {
- Console.WriteLine("Find a invalid link...");
-
- XmlNode node = this._writerDoc.CreateNode(XmlNodeType.Element, "invalidUrl", null);
- XmlNode nodeUrl = this._writerDoc.CreateNode(XmlNodeType.Attribute, "url", null);
- XmlNode nodeReferUrl = this._writerDoc.CreateNode(XmlNodeType.Attribute, "refer", null);
- XmlNode nodeReason = this._writerDoc.CreateNode(XmlNodeType.Attribute, "reason", null);
-
- nodeUrl.Value = propertyBag.OriginalUrl;
- nodeReferUrl.Value = propertyBag.OriginalReferrerUrl;
- nodeReason.Value = ((int)propertyBag.StatusCode).ToString();
-
- node.Attributes.SetNamedItem(nodeUrl);
- node.Attributes.SetNamedItem(nodeReferUrl);
- node.Attributes.SetNamedItem(nodeReason);
-
- this._writerDoc.DocumentElement.AppendChild(node);
- }
- }
- }
而外部程式只要如此呼叫即可:
[C#]
- static void Main(string[] args)
- {
- Console.WriteLine("Scanning...");
- InvalidLinkDetector detector = new InvalidLinkDetector("http://msdn.microsoft.com", 10, 4);
- detector.Run();
- }
這支程式的執行步驟有兩個,一個是剖析 HTML 的 HtmlDocumentProcessor,它會分析下載的 HTML 資源,並且取出裡面的連結,而 ScanResultWriter 則是會利用 Crawler 傳入的 PropertyBag 事件參數來判斷是否該要求是 HTTP 404,如果是的話會寫入資料到 XmlDocument,並且在 Crawler 結束執行時(CrawlFinished 事件引發)儲存到磁碟中。
NOTE
任何要作為 Crawler 執行步驟的物件,都必須繼承自 IPipelineStep 介面,才可以被 Crawler 取用。
此程式執行的畫面如下:
而偵測到無效連結時的回報文件格式如下:
[XML]
- "/vs2008/products/cc268305.aspx" refer="http://msdn.microsoft.com/en-us/default.aspx" reason="404" />
- url 是偵測的網址。
- refer 是該網址的來源網址。
- reason 是原因,以代碼表示,例如 404 是找不到網頁。
有了這件 XML 文件,讀者可自行設計套用它的 XSLT 轉換格式檔,讓它可以呈現具親和力的報表樣式。
沒有留言:
張貼留言