轉載自 這裡
前言 :
這篇文章介紹了HtmlParser 開源包和 HttpClient 開源包的使用,在此基礎上實現了一個簡易的網絡爬蟲(Crawler),來說明如何使用HtmlParser 根據需要處理Internet 上的網頁,以及如何使用HttpClient 來簡化Get 和Post 請求操作,構建強大的網絡應用程序.
HttpClient 與HtmlParser 簡介 :
- HttpClient 簡介
HTTP 協議是現在的因特網最重要的協議之一。除了WEB瀏覽器之外, WEB服務,基於網絡的應用程序以及日益增長的網絡計算不斷擴展著HTTP協議的角色,使得越來越多的應用程序需要HTTP協議的支持。雖然JAVA類庫.net包提供了基本功能,來使用HTTP協議訪問網絡資源,但是其靈活性和功能遠不能滿足很多應用程序的需要。而Jakarta Commons HttpClient 組件尋求提供更為靈活,更加高效的HTTP協議支持,簡化基於HTTP協議的應用程序的創建. HttpClient 提供了很多的特性,支持最新的HTTP標準,可以訪問這裡了解更多關於HttpClinet的詳細信息。目前有很多的開源項目都用到了HttpClient提供的HTTP功能,登陸網址可以查看這些項目. 本文中使用HttpClinet提供的類庫來訪問和下載Internet上面的網頁,在後續部分會詳細介紹到其提供的兩種請求網絡資源的方法: Get請求和Post請求.
- HtmlParser 簡介
當今的Internet上面有數億記的網頁,越來越多應用程序將這些網頁作為分析和處理的數據對象。這些網頁多為半結構化的文本,有著大量的標籤和嵌套的結構。當我們自己開發一些處理網頁的應用程序時,會想到要開發一個單獨的網頁解析器,這一部分的工作必定需要付出相當的精力和時間。事實上,做為JAVA應用程序開發者, HtmlParser為其提供了強大而靈活易用的開源類庫,大大節省了寫一個網頁解析器的開銷。HtmlParser 是http://sourceforge.net上活躍的一個開源項目,它提供了線性和嵌套兩種方式來解析網頁,主要用於html網頁的轉換(Transformation)以及網頁內容的抽取(Extraction) 。HtmlParser有如下一些易於使用的特性:過濾器(Filters),訪問者模式(Visitors),處理自定義標籤以及易於使用的JavaBeans。正如HtmlParser首頁所說:它是一個快速,健壯以及嚴格測試過的組件;以它設計的簡潔,程序運行的速度以及處理Internet上真實網頁的能力吸引著越來越多的開發者。本文中就是利用HtmlParser裡提取網頁裡的鏈接,實現簡易爬蟲裡的關鍵部分。HtmlParser最新的版本是 HtmlParser1.6,可以登陸這裡下載其源碼、 API參考文檔以及JAR包.
HttpClient 基本類庫使用 :
HttpClinet 提供了幾個類來支持HTTP 訪問。下面我們通過一些示例代碼來熟悉和說明這些類的功能和使用。HttpClient 提供的HTTP 的訪問主要是通過GetMethod 類和PostMethod 類來實現的,他們分別對應了HTTP Get 請求與Http Post 請求 :
- GetMethod
使用GetMethod 來訪問一個URL 對應的網頁,需要如下一些步驟 :
下面代碼展示了這些步驟,其中的註釋對代碼進行了較詳細的說明 :
這裡值得注意的幾個地方是 :
在處理返回結果的時候可以根據自己的需要,進行相應的處理. (如保存網頁)
- PostMethod
PostMethod 方法與GetMethod 方法的使用步驟大體相同. 但是由於PostMethod 使用的是HTTP 的Post 請求,因而請求參數的設置與GetMethod 有所不同. 在GetMethod 中,請求的參數直接寫在URL 裡,一般以這樣形式出現:http://hostname:port//file?name1=value1&name2=value …。請求參數是name,value 對。比如我想得到百度搜索 "Thinking In Java" 的結果網頁,就可以使GetMethod 的構造方法中的url 為:http://www.baidu.com/s?wd=Thinking+In+Java . 而PostMethod 則可以模擬網頁裡表單提交的過程,通過設置表單裡post 請求參數的值,來動態的獲得返回的網頁結果. 以下代碼展示瞭如何創建一個Post 對象,並設置相應的請求參數 :
HtmlParser 基本類庫使用 :
HtmlParser 提供了強大的類庫來處理Internet 上的網頁,可以實現對網頁特定內容的提取和修改。下面通過幾個例子來介紹HtmlParser 的一些使用. 這些例子其中的代碼,有部分用在了後面介紹的簡易爬蟲中. 網頁是一個半結構化的嵌套文本文件,有類似XML 文件的樹形嵌套結構. 使用HtmlParser 可以讓我們輕易的迭代遍歷網頁的所有節點 :
上面的中有兩個方法 :
* private static void processNodeList(NodeList list, String keyword)
* public static void extractKeyWordText(String url, String keyword)
上述代碼展示如何迭代網頁,更多的工作可以在此基礎上展開。比如找到網頁某個特定的內部節點,其實就可以在遍歷所有的節點基礎上來判斷,看被迭代的節點是否滿足特定的需要.
- 使用NodeFilter
NodeFilter 是一個接口,任何一個自定義的Filter 都需要實現這個接口中的boolean accept() 方法。如果希望迭代網頁節點的時候保留當前節點,則在節點條件滿足的情況下返回true;否則返回false。HtmlParse 裡提供了很多實現了NodeFilter 接口的類,下面就一些筆者所用到的,以及常用的Filter 做一些介紹 :
* 對Filter做邏輯操作的Fitler有 AndFilter,NotFilter,OrFilter,XorFilter
* 判斷節點的孩子,兄弟,以及父親節點情況的Filter有 HasChildFilter, HasParentFilter,HasSiblingFilter.
* 判斷節點本身情況的Filter有 HasAttributeFilter : 判讀節點是否有特定屬性;LinkStringFilter : 判斷節點是否是具有特定模式(pattern) url的節點;TagNameFilter : 判斷節點是否具有特定的名字;NodeClassFilter : 判讀節點是否是某個HtmlParser定義好的Tag類型.
還有其他的一些Filter 在這裡不一一列舉了,可以在 org.htmlparser.filters 下找到. 下面代碼展示瞭如何使用上面提到過的一些 filter 來抽取網頁中的 a 標籤的 href 屬性值, img 標籤與 frame 標籤中的 src 屬性值 :
- 簡單強大的StringBean
如果你想要網頁中去掉所有的標籤後剩下的文本,那就是用StringBean 吧。以下簡單的代碼可以幫你解決這樣的問題 :
HtmlParser 提供了強大的類庫來處理網頁,由於本文旨在簡單的介紹,因此只是將與筆者後續爬蟲部分有關的關鍵類庫進行了示例說明. 感興趣的可以專門來研究一下HtmlParser 更為強大的類庫!
簡易爬蟲的實現流程說明 :
HttpClient 提供了便利的HTTP 協議訪問,使得我們可以很容易的得到某個網頁的源碼並保存在本地;HtmlParser 提供瞭如此簡便靈巧的類庫,可以從網頁中便捷的提取出指向其他網頁的超鏈接。筆者結合這兩個開源包,構建了一個簡易的網絡爬蟲 :
- 爬蟲(Crawler) 原理
學過數據結構的讀者都知道有向圖這種數據結構。如下圖所示,如果將網頁看成是圖中的某一個節點,而將網頁中指向其他網頁的鏈接看成是這個節點指向其他節點的邊,那麼我們很容易將整個Internet 上的網頁建模成一個有向圖。理論上,通過遍曆算法遍歷該圖,可以訪問到Internet 上的幾乎所有的網頁。最簡單的遍歷就是寬度優先以及深度優先。以下筆者實現的簡易爬蟲就是使用了寬度優先的爬行策略 :
- 簡易爬蟲實現流程
在看簡易爬蟲的實現代碼之前,先介紹一下簡易爬蟲爬取網頁的流程 :
各個類的源碼以及說明 :
對應上面的流程圖,簡易爬蟲由下面幾個類組成,各個類職責如下 :
下面是各個類的源碼,代碼中的註釋有比較詳細的說明 :
前言 :
這篇文章介紹了HtmlParser 開源包和 HttpClient 開源包的使用,在此基礎上實現了一個簡易的網絡爬蟲(Crawler),來說明如何使用HtmlParser 根據需要處理Internet 上的網頁,以及如何使用HttpClient 來簡化Get 和Post 請求操作,構建強大的網絡應用程序.
HttpClient 與HtmlParser 簡介 :
- HttpClient 簡介
HTTP 協議是現在的因特網最重要的協議之一。除了WEB瀏覽器之外, WEB服務,基於網絡的應用程序以及日益增長的網絡計算不斷擴展著HTTP協議的角色,使得越來越多的應用程序需要HTTP協議的支持。雖然JAVA類庫.net包提供了基本功能,來使用HTTP協議訪問網絡資源,但是其靈活性和功能遠不能滿足很多應用程序的需要。而Jakarta Commons HttpClient 組件尋求提供更為靈活,更加高效的HTTP協議支持,簡化基於HTTP協議的應用程序的創建. HttpClient 提供了很多的特性,支持最新的HTTP標準,可以訪問這裡了解更多關於HttpClinet的詳細信息。目前有很多的開源項目都用到了HttpClient提供的HTTP功能,登陸網址可以查看這些項目. 本文中使用HttpClinet提供的類庫來訪問和下載Internet上面的網頁,在後續部分會詳細介紹到其提供的兩種請求網絡資源的方法: Get請求和Post請求.
- HtmlParser 簡介
當今的Internet上面有數億記的網頁,越來越多應用程序將這些網頁作為分析和處理的數據對象。這些網頁多為半結構化的文本,有著大量的標籤和嵌套的結構。當我們自己開發一些處理網頁的應用程序時,會想到要開發一個單獨的網頁解析器,這一部分的工作必定需要付出相當的精力和時間。事實上,做為JAVA應用程序開發者, HtmlParser為其提供了強大而靈活易用的開源類庫,大大節省了寫一個網頁解析器的開銷。HtmlParser 是http://sourceforge.net上活躍的一個開源項目,它提供了線性和嵌套兩種方式來解析網頁,主要用於html網頁的轉換(Transformation)以及網頁內容的抽取(Extraction) 。HtmlParser有如下一些易於使用的特性:過濾器(Filters),訪問者模式(Visitors),處理自定義標籤以及易於使用的JavaBeans。正如HtmlParser首頁所說:它是一個快速,健壯以及嚴格測試過的組件;以它設計的簡潔,程序運行的速度以及處理Internet上真實網頁的能力吸引著越來越多的開發者。本文中就是利用HtmlParser裡提取網頁裡的鏈接,實現簡易爬蟲裡的關鍵部分。HtmlParser最新的版本是 HtmlParser1.6,可以登陸這裡下載其源碼、 API參考文檔以及JAR包.
HttpClient 基本類庫使用 :
HttpClinet 提供了幾個類來支持HTTP 訪問。下面我們通過一些示例代碼來熟悉和說明這些類的功能和使用。HttpClient 提供的HTTP 的訪問主要是通過GetMethod 類和PostMethod 類來實現的,他們分別對應了HTTP Get 請求與Http Post 請求 :
- GetMethod
使用GetMethod 來訪問一個URL 對應的網頁,需要如下一些步驟 :
下面代碼展示了這些步驟,其中的註釋對代碼進行了較詳細的說明 :
這裡值得注意的幾個地方是 :
在處理返回結果的時候可以根據自己的需要,進行相應的處理. (如保存網頁)
- PostMethod
PostMethod 方法與GetMethod 方法的使用步驟大體相同. 但是由於PostMethod 使用的是HTTP 的Post 請求,因而請求參數的設置與GetMethod 有所不同. 在GetMethod 中,請求的參數直接寫在URL 裡,一般以這樣形式出現:http://hostname:port//file?name1=value1&name2=value …。請求參數是name,value 對。比如我想得到百度搜索 "Thinking In Java" 的結果網頁,就可以使GetMethod 的構造方法中的url 為:http://www.baidu.com/s?wd=Thinking+In+Java . 而PostMethod 則可以模擬網頁裡表單提交的過程,通過設置表單裡post 請求參數的值,來動態的獲得返回的網頁結果. 以下代碼展示瞭如何創建一個Post 對象,並設置相應的請求參數 :
- PostMethod postMethod = new PostMethod("http://dict.cn/");
- postMethod.setRequestBody(new NameValuePair[]{new NameValuePair("q","java")});
HtmlParser 基本類庫使用 :
HtmlParser 提供了強大的類庫來處理Internet 上的網頁,可以實現對網頁特定內容的提取和修改。下面通過幾個例子來介紹HtmlParser 的一些使用. 這些例子其中的代碼,有部分用在了後面介紹的簡易爬蟲中. 網頁是一個半結構化的嵌套文本文件,有類似XML 文件的樹形嵌套結構. 使用HtmlParser 可以讓我們輕易的迭代遍歷網頁的所有節點 :
上面的中有兩個方法 :
* private static void processNodeList(NodeList list, String keyword)
* public static void extractKeyWordText(String url, String keyword)
上述代碼展示如何迭代網頁,更多的工作可以在此基礎上展開。比如找到網頁某個特定的內部節點,其實就可以在遍歷所有的節點基礎上來判斷,看被迭代的節點是否滿足特定的需要.
- 使用NodeFilter
NodeFilter 是一個接口,任何一個自定義的Filter 都需要實現這個接口中的boolean accept() 方法。如果希望迭代網頁節點的時候保留當前節點,則在節點條件滿足的情況下返回true;否則返回false。HtmlParse 裡提供了很多實現了NodeFilter 接口的類,下面就一些筆者所用到的,以及常用的Filter 做一些介紹 :
* 對Filter做邏輯操作的Fitler有 AndFilter,NotFilter,OrFilter,XorFilter
* 判斷節點的孩子,兄弟,以及父親節點情況的Filter有 HasChildFilter, HasParentFilter,HasSiblingFilter.
* 判斷節點本身情況的Filter有 HasAttributeFilter : 判讀節點是否有特定屬性;LinkStringFilter : 判斷節點是否是具有特定模式(pattern) url的節點;TagNameFilter : 判斷節點是否具有特定的名字;NodeClassFilter : 判讀節點是否是某個HtmlParser定義好的Tag類型.
還有其他的一些Filter 在這裡不一一列舉了,可以在 org.htmlparser.filters 下找到. 下面代碼展示瞭如何使用上面提到過的一些 filter 來抽取網頁中的 a 標籤的 href 屬性值, img 標籤與 frame 標籤中的 src 屬性值 :
- HttpParserDemo 部分代碼 :
- // 獲取一個網頁上所有的鏈接和圖片鏈接
- public static void extracLinks(String url) {
- try {
- Parser parser = new Parser(url);
- parser.setEncoding("gb2312");
- // 過濾 frame 標籤的filter,用來提取frame 標籤裡的src 屬性所、表示的鏈接
- NodeFilter frameFilter = new NodeFilter() {
- @Override
- public boolean accept(Node node) {
- if (node.getText().startsWith("frame src=")) {
- return true;
- }
- return false;
- }
- };
- // OrFilter 來設置過濾 a 標籤,img 標籤和 frame 標籤,三個標籤是or 的關係
- OrFilter orFilter = new OrFilter(
- new NodeClassFilter(LinkTag.class), new NodeClassFilter(
- ImageTag.class));
- OrFilter linkFilter = new OrFilter(orFilter, frameFilter);
- // 得到所有經過過濾的標籤
- NodeList list = parser.extractAllNodesThatMatch(linkFilter);
- for (int i = 0; i < list.size(); i++) {
- Node tag = list.elementAt(i);
- if (tag instanceof LinkTag)// a 標籤
- {
- LinkTag link = (LinkTag) tag;
- String linkUrl = link.getLink();// url
- String text = link.getLinkText();// 鏈接文字
- System.out.println(linkUrl + "**********" + text);
- } else if (tag instanceof ImageTag)// img 標籤
- {
- ImageTag image = (ImageTag) list.elementAt(i);
- System.out.print(image.getImageURL() + "********");// 圖片地址
- System.out.println(image.getText());// 圖片文字
- } else// frame 標籤
- {
- // 提取frame 裡src 屬性的鏈接如 frame src="test.html"
- String frame = tag.getText();
- int start = frame.indexOf("src=");
- frame = frame.substring(start);
- int end = frame.indexOf(" ");
- if (end == -1)
- end = frame.indexOf(">");
- frame = frame.substring(5, end - 1);
- System.out.println(frame);
- }
- }
- } catch (ParserException e) {
- e.printStackTrace();
- }
- }
- 簡單強大的StringBean
如果你想要網頁中去掉所有的標籤後剩下的文本,那就是用StringBean 吧。以下簡單的代碼可以幫你解決這樣的問題 :
- StringBean sb = new StringBean();
- sb.setLinks(false);//設置結果中去點鏈接
- sb.setURL(url);//設置你所需要濾掉網頁標籤的頁面url
- System.out.println(sb.getStrings());//打印結果
簡易爬蟲的實現流程說明 :
HttpClient 提供了便利的HTTP 協議訪問,使得我們可以很容易的得到某個網頁的源碼並保存在本地;HtmlParser 提供瞭如此簡便靈巧的類庫,可以從網頁中便捷的提取出指向其他網頁的超鏈接。筆者結合這兩個開源包,構建了一個簡易的網絡爬蟲 :
- 爬蟲(Crawler) 原理
學過數據結構的讀者都知道有向圖這種數據結構。如下圖所示,如果將網頁看成是圖中的某一個節點,而將網頁中指向其他網頁的鏈接看成是這個節點指向其他節點的邊,那麼我們很容易將整個Internet 上的網頁建模成一個有向圖。理論上,通過遍曆算法遍歷該圖,可以訪問到Internet 上的幾乎所有的網頁。最簡單的遍歷就是寬度優先以及深度優先。以下筆者實現的簡易爬蟲就是使用了寬度優先的爬行策略 :
- 簡易爬蟲實現流程
在看簡易爬蟲的實現代碼之前,先介紹一下簡易爬蟲爬取網頁的流程 :
各個類的源碼以及說明 :
對應上面的流程圖,簡易爬蟲由下面幾個類組成,各個類職責如下 :
下面是各個類的源碼,代碼中的註釋有比較詳細的說明 :
沒有留言:
張貼留言