1. 程式人生 > >網路採集器Demo:Jsoup+Java多執行緒實現[爬蟲](上)

網路採集器Demo:Jsoup+Java多執行緒實現[爬蟲](上)

裡面最簡單,但是很常用的一個部分,就是網路爬蟲,從網頁上獲取文字資訊

這裡用到兩個工具,一個就是Java多執行緒(基於Java5 以上的執行緒池模式,區別於過時的Runable),另外一個是一個小工具:Jsoup,用於解析html網頁,獲取其中的內容,關於Jsoup的使用,這是一個技術活,在下面的描述中會介紹一些基礎操作,但主要還是需要師弟們自己去學習:http://www.open-open.com/jsoup/

demo的功能是,爬取新浪主頁的新聞文字內容。

下面我們一步一步來:

新浪首頁即是我們的種子頁面,首先我們需要獲取新浪首頁上的全部內容連結

1.用Jsoup獲得種子頁面的html程式碼

public class JsoupGetDocument {

	public static Document getDocumentByJsoupBasic(String url) {
		try {

			// 設定連線超時和讀數超時
			// 設定忽略過期頁面
			return Jsoup.connect(url).timeout(120000).ignoreHttpErrors(true)
					.ignoreContentType(true).get();

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();

			return null;
		}
	}
}
第7行解釋:連結到要獲取html程式碼的url,設定等待時間,忽略http錯誤,忽略網頁內容編碼格式

返回的是Jsoup中的Docment物件,內包含html程式碼以及其結構資訊,它可以用作我們進一步對獲取的html程式碼分析。

2.獲得種子頁面上的全部有效連結

public class FetchLinksFromPage {

	// 獲得所有的連結
	public Set<ExactLinks> getAllUrl(String seedUrl) {
		Set<ExactLinks> urlSet = new HashSet<ExactLinks>();

		try {
			Document docPage = JsoupGetDocument
					.getDocumentByJsoupBasic(seedUrl);
			Elements eleLinks = docPage.select("a[href]");
			for (Element eleLink : eleLinks) {
				String url = eleLink.attr("abs:href");
				String urlMD5 = new TransMD5().getMD5Code(url);

				urlSet.add(new ExactLinks(url, urlMD5));
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return urlSet;
	}

	// 過濾出有用的url
	public Set<ExactLinks> filterUrl(String seedUrl) {

		Set<ExactLinks> urlSet = this.getAllUrl(seedUrl);
		Set<ExactLinks> filterLinks = new HashSet<ExactLinks>();

		for (String urlModel : CrawlUnitParam.SINA_URL_MODEL) {

			for (ExactLinks links : urlSet) {
				if (links.getUrl().contains(urlModel)) {
					filterLinks.add(links);
				}
			}
		}

		return filterLinks;
	}
}
第8行獲得頁面Docment物件後,第10行獲得全部帶有連結資訊的元素塊,這裡Elements物件是一個集合,其中每一個Element都是單獨一個含有連結的html子塊,這裡要注意,select方法是Jsoup精髓,傳入的引數是一個匹配html程式碼位置的模式串,關於這個模式串的設計,就是之前說的技術活,學習:http://www.open-open.com/jsoup/selector-syntax.htm。下面的迴圈是對每個子塊中的連結元素進行提取,並加入結果集合。

getAllUrl返回的是種子頁面上全部錨鏈接的集合,注意這個集合用的是HashSet,可以自動排除重複的連結,可以自己設計一個ExactLinks類,需要重寫hashCode和equals函式。但是,到這一步並沒有結束,filterUrl方法是為了過濾無用的連結,CrawlUnitParam.SINA_URL_MODEL中儲存的是有用連結的模式集合,可以自己設計,匹配成功才加入最終的集合,並返回。我的模式集合是:

public class CrawlUnitParam {

	public static List<String> SINA_URL_MODEL = new ArrayList<String>();
	static {
		SINA_URL_MODEL.add(".shtml");
		SINA_URL_MODEL.add(".html");
	}
}
可以自己列印一下解析出來的全部連結。

3.解析獲得每個連結中的文字內容

我們將上面的每個連結傳入函式getParagraphContent,返回該頁中有效的文字內容

public class FetchPaContentFromPage {

	public String getParagraphContent(String pageUrl) {

		String paragraphContent = "";

		try {
			Document docPage = JsoupGetDocument
					.getDocumentByJsoupBasic(pageUrl);
			Elements eleParagraphs = docPage.select("p");
			for (Element eleParagraph : eleParagraphs) {
				String content = eleParagraph.text();

				paragraphContent += content;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();

			return null;
		}

		return paragraphContent;
	}
}
同樣在第8行獲得頁面的Docment物件之後,下面就是對包含有效文字的html子塊進行抽取,還是使用select方法,至於什麼是有效的文字資訊,這些內容包含在具有什麼特點的html子塊中,需要我們分析網站頁面的html程式碼,新浪新聞的有效資訊就包含在<p></p>子塊中,於是我們如上進行抽取。

下面迴圈中的text方法是獲得html程式碼子塊中包含的文字資訊,對所有這樣的文字資訊進行拼接,返回。

好了,經過以上的步驟,相信師弟們自己完成一個序列的採集器沒有問題了吧,但是我並沒有那樣實現,下一節將描述一個並行實現的採集器,這樣我們會獲得更高的效率。