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[.-]]+@[\\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倍,厉害厉害。

猜你喜欢

转载自blog.csdn.net/wl_Honest/article/details/83147786
今日推荐