1. 程式人生 > >Jsoup簡單例子2.0——多執行緒爬取網頁內的郵箱

Jsoup簡單例子2.0——多執行緒爬取網頁內的郵箱

上一篇文章講了利用Jsoup爬取貼吧帖子裡的郵箱,雖然爬取成功了,但我對效率有所追求。10頁的帖子爬取了兩百多個郵箱,最快用時8秒,一般需要9秒。在思考了一下怎麼提升效率後,決定採用多執行緒的方式爬取網頁內的郵箱。廢話不多說,直接上程式碼。

引入Jsoup的jar包此處省略,沒有的可以檢視上篇文章。


import java.io.IOException;
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;


/**
 * 多執行緒爬取郵箱
 * @author pactera
 *
 */
public class JsoupTest4 {
	/**
	 * Queue:先入先出(FIFO)的資料結構
	 * LinkedBlockingQueue:一個由連結節點支援的可選有界佇列
	 */
	//等待爬取的url
	private static volatile Queue<String> queue = new LinkedBlockingQueue<String>();
	//爬取過的url
	private static volatile Set<String> allOverUrl=new HashSet<>();
	//匯流排程5條
	private static int MAX_THREAD=5;
	//開始時間
	private static long startTime=0;
	//記錄獲取的郵箱個數
	private static int emailCount=0;
	//爬取帖子的頁數(10頁)
	private static AtomicInteger pageCount=new AtomicInteger(10);
	
	public static void main(String[] args) {
		for(int i =1;i <= pageCount.get();i++) {
			String url = "https://tieba.baidu.com/p/3349997454?pn="+i;
			//將獲取的url放入等待佇列中
			queue.add(url);
		}
		//記錄開始時間
		startTime = System.currentTimeMillis();
		for(int i = 0;i < MAX_THREAD;i++) {
			new JsoupTest4().new MyThread().start();
		}
	}
	
	/**
	 * 網頁資料爬取
	 */
	public static void work() {
		String url = queue.poll();
		//檢測執行緒是否執行
		System.out.println("當前執行:"+Thread.currentThread().getName()+" 爬取執行緒處理爬取:"+url);
		try {
			Document document = Jsoup.connect(url)
					//偽裝成瀏覽器進行抓取
					.header("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0")
					.get(); 
			Element main = document.getElementById("j_p_postlist");
			Elements content = main.select("div.l_post_bright")
					.select("div.d_post_content_main")
					.select("div.p_content")
					.select("cc")
					.select("div.d_post_content");
			
			//遍歷每一帖的內容
			for (Element element : content) {
				String Content = element.text();
				//正則表示式判斷郵箱
				String patternStr = "[\\w[.-]]
[email protected]
[\\w[.-]]+\\.[\\w]+"; Pattern pattern = Pattern.compile(patternStr); Matcher matcher = pattern.matcher(Content); //如果含有郵箱,獲取到的郵箱個數emailCount+1,並輸出 if(matcher.find()) { emailCount++; //輸出郵箱 //System.out.println(matcher.group()); } } } catch (IOException e) { e.printStackTrace(); } //將當前url歸列到alloverurl中 allOverUrl.add(url); System.out.println(url+"網頁爬取完成,已爬取數量:"+allOverUrl.size()); //繼續爬取其他連結 if(allOverUrl.size() == pageCount.get()) { long endTime = System.currentTimeMillis(); System.out.println("爬取結束,耗時:"+(endTime - startTime)/1000+"s"); System.out.println("獲取了"+emailCount+"個郵箱"); } } /** * 執行緒分配任務 * @author pactera * */ public class MyThread extends Thread{ @Override public void run() { do{ work(); }while(queue.size() > 0); } } }

最後比較一下效率,先看單執行緒的用時:

多執行緒用時:

 開啟了5個執行緒,效率提升了5倍,厲害厲害。