.NET平台上實現網站內容采摘的關鍵技術


這些天,老板交給我一個任務,把某個網站的文章全部下載下來,並分類保存好。

雖然以前有聽說過這種需求,但是我卻從來沒有做過這樣的應用。並不是因為不會做,而是不想做。首先覺得這其中沒有什么高深的技術,其次我一向都認為采摘別人網站的內容沒什么用,優秀的內容絕不是從別人那里抄來的。我想這些都是我以往的年少無知。其實,有需求也就有價值。技術也沒有高深不高深,不懂就高深,懂了就不高深。

好吧,那么就開始干吧。

我首先使用的是PHP,而且還是寫網頁腳本,因為我電腦都會配置HTTP服務和PHP環境,而且PHP基本上算是我最熟悉的技術平台了。 因為我沒有想過要做一個完整的工具,我只是想電腦幫我做點重復的工作,做過就算,所以我沒有做軟件開發過程中基本的分析的設計。 就想了一下程序要做的幾件事,如下: 一、下載HTML文件。 二、從HTML代碼中截取文章內容。 三、下載文章內容中的圖像文件。

首先做第一件事,下載HTML文件。 對PHP來說關鍵在於一個函數file_get_contents(),這個函數可以通過一個HTTP地址讀取HTTP文件的內容,就像在瀏覽器中輸入一個地址,瀏覽器就會獲得返回的HTML文本一樣,你可以把它看作一個迷你的瀏覽器。除此之外,剩下的就是在硬盤上創建文本文件來保存HTML代碼了,這個通過PHP的文件系統函數就可以完成。 這件事很順利。

第二件事,從已下載的HTML文件中截取文章內容。 因為HTML頁上除了文章的內容外,還會存在很多額外的內容,如網站的導航菜單、側欄、廣告、Javascript腳本等,這些東西都是不要的,我只要文章標題和正文。 對於PHP來說,我第一時間想到的是用正則表達式去匹配,但很快覺得這種方式過於原始,太底層了,在編程技術如些發達的今天,一定存在更高層的處理方式。於是翻翻PHP手冊,函數庫中有一章是XML處理的,看看,果然,里面有大量的函數和類,已經實現了把XML文檔作為一個對象來處理,也就是XML DOM,通過這些函數和類,PHP可以像Javascript在瀏覽器中處理HTML元素一樣去處理HTML文檔。 但是,這時寫PHP腳本已經讓我感到有點累了,不停地改腳本然后按F5,而且要在代碼中控制頁面跳轉,非常不好玩,我忽然覺得這些事情應該通過寫桌面程序來做。 於是,我理所當然地想到了.NET。哇,我終於進入正題了。

.NET真的不是這錯的平台,具體怎么好,我就不在這里幫微軟打廣告了。 上面的第一件事也可以用.NET平台來做,原理是一樣的,只是具體代碼不一樣,在.NET中一般是通過幾個類來完成,.NET是一個完全面向對象的編程平台,所以什么都是對象,下載HTTP文件主要是使用System.Net命名空間中的HttpWebRequest、HttpWebResponse兩個類。 HttpWebRequest可以包裝一個URL地址,通過GetResponse方法獲取一個HttpWebResponse對象,此HttpWebResponse對象包含了HTTP服務器返回的數據。除此之外就是文件系統的IO操作了,就不再多說,畢竟是只說關鍵技術嘛。

現在說說在.NET中做第二件事,也就是從已下載的HTML文件中截取文章內容。上面說過了,用正則表達式是一種很低級的方式,如果是十分簡單的操作那么用正則還是挺不錯的選擇,但是如果你要查找元素,修改節點內容及屬性值,那么使用正則將是一種災難。在.NET中,同樣提供了XML DOM的支持,這些類被放在System.Xml命名空間中。

在使用.NET的XmlDocument類時,有一件事情特別值得一說。 剛開始的時候,發現XmlDocument對象的LoadXml方法非常慢。這個方法的功能是把一段XML字符串加載為XmlDocument對象。我發現在它加載一個XML文檔需要差不多一分鍾,這樣的效率我認為絕對是不正常的。於是上網找資料,發現原來是DOCTYPE的問題,原來LoadXml跑去W3C網站下載dtd文件了,怪之得慢啊。解決方法是,把dtd文件下載到本地的HTTP服務中,並建好相對應的目錄,在Windows系統的host文件中把W3C的域名解析為本機,這樣速度就變快了,幾乎是一閃而過。如果覺得弄本地HTTP服務麻煩,那么也可以直接放在文件系統中,然后批修改HTML的DOCTYPE,把dtd文件的地址改為本地的相對路徑。

好吧第二件事情就這樣搞定了。

第三件事,下載文章中的圖像,這件事其實是第一件事和第二件事的結合。 首先需要用XML DOM讀取img元素的src屬性,用這個屬性值對下載圖像文件。 這里下載的文件和第一件事中的文件有點不一樣,因為圖像文件不是文本文件,所以要用二進制流對象去進行讀寫操作,主要是BinaryReader和BinaryWriter對象。在這個操作的過程中,特別要注意的是,獲取響應流的字節長度時,不能使用流對象的Length屬性,這會提示“此流不支持查找操作”,可能是這是來自網絡原因,和.NET本身的實現有關。那么怎么獲取響應流的長度呢,用HttpWebResponse對象的ContentLength屬性。 把下載的圖像文件保存到本地硬盤后,需要通過XML DOM修改對應的img元素的src屬性為本地相對路徑,這樣才可以讓網頁正確顯示本地的圖像。

到此為止,相關技術已經基本介紹完畢,還有一點算是題外的技術要點很值得講一下的,那就是多線程技術。 像我這樣的.NET菜鳥,是從來沒有寫過多線程的,所以,寫這種長時間工作的程序時,會發現程序在運行時,它的窗口卡死了。這是由於主線程一直在內部處理數據,而無瑕響應圖形介面,直到程序結束處理工作時,介面才會響應。這樣的話,原先想好的在程序處理數據的過程中不斷更新窗口信息來顯示處理進程的計划就無法做到了。解決的辦法就是使用多線程。剛開始使用多線程時,會遇到線程安全的問題,會收到不能跨線程調用控件的異常,如果想以后再花時間補上線程同步的知識,那么你可以先把.NET中控件的線程安全檢查去掉,方法是把System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls的值設為false。

好吧,基本上就這樣了,有興趣的朋友找時間去試試吧。 主要是作點筆記,說得不好的地方還請大家指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM