`
happysoul
  • 浏览: 398160 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

使用线程池ThreadPoolExecutor 抓取论坛帖子列表

阅读更多
早前经常在网站上面下载动画和日剧,后来BT没有了~ 就只能逛论坛了!
现在的论坛大家也都了解~ 广告铺天盖地,打开个页面有时候能跳出来3-4个广告
对我来说常去的也就是猪猪字幕,不过那些垃圾广告实在没有办法,再就是垃圾服务器访问速度巨慢无比,点个下一页不知道要等N久~~
所以想到了 我每次只需要帖子列表 具体想看哪个再打开页面去下载种子(其实再做一个访问帖子链接 下载种子的方法也不难,感觉还是需要看到截图和宣传画才能决定是否下载就没有继续做)

回到技术方面,普通的多线程很难对线程数量进行控制,只要运行,所有队列里面的都会运行,受制约于带宽问题,很多页面本来是可以打开的,因为网络没有读到数据,于是想到了线程池,也就是保证池中每次只有几个线程在运行,早前发现的方法都是用 ThreadGroup 和 WatchThread方法解决这个问题,开发和维护起来就稍显的复杂了。除非是你的线程间要传递数据,否则并行的线程完全够用了

//线程、最大池、存活时间、存活时间单位、队列
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 20, 1, TimeUnit.HOURS, new LinkedBlockingQueue());
循环 executor.execute(new XxxThread(xxx,xxx)); 将线程加入池中

我也没有太细致的阅读到这部分的源码,所以就算是抛砖引玉的把方法抛出来供大家使用和研究了。
保存数据库之类的方法我都删除了,毕竟为了这东西没必要再去让运行的人都去装个Mysql之类的数据库

线程入口程序
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class BbsThread implements Runnable {
	private int fid;
	private int lastyear;
	
	public int getFid() {
		return fid;
	}
	public void setFid(int fid) {
		this.fid = fid;
	}
	public int getLastyear() {
		return lastyear;
	}
	public void setLastyear(int lastyear) {
		this.lastyear = lastyear;
	}

	public BbsThread(){}
	public BbsThread(int fid,int lastyear){
		this.fid = fid;
		this.lastyear = lastyear;
	}

	//run方法
	public void run() {
		System.out.println("线程启动,开始抓取数据");
		BBS.t(1,2,fid,lastyear);	//每个线程只抓取1-2页
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static void main(String[] args) {
//	    BlockingQueue queue = new LinkedBlockingQueue();
	    //线程、最大池、存活时间、存活时间单位、队列
	    ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 20, 1, TimeUnit.HOURS, new LinkedBlockingQueue());   
	    int[] fids = {66,200,168,306};
		int lastyear = 2010; 	//不能是2010年前的,可以是2010
		for(int i=0;i<fids.length;i++){
			executor.execute(new BbsThread(fids[i],lastyear));
		}
	    executor.shutdown();  
	}
}



后面的这个是抓取论坛数据的部分,也可以单独运行,不过那可就真是单线程的了
package com.test;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class BBS {
	
	//单独运行抓取方法,线程池请运行 BbsThread
	public static void main(String[] args) {
		int[] fids = {66,200,168,306};
		int lastyear = 2010; 	//不能是2010年前的,可以是2010
		for(int i=0;i<fids.length;i++){
			t(1,8,fids[i],lastyear);	//抓取页数1-8页
		}
	}

	public static void t(int from, int end, int fid, int lastyear) {
		String url = "http://www.subpig.net/forumdisplay.php?fid="+fid+"&page=";
		if (from > end)
			return;
		for (; from <= end; from++) {
			int i = 1;
			System.out.println(url+from);
			String htmltext = gethtml("gbk", url + from).replaceAll("\\t", "");

			String regex = "<tbody id=\"[\\w]+_[\\d]+\"(.*?)</tbody>";
			Matcher mc = regex(htmltext, regex);
			while (mc.find()) {
				String txt = mc.group(1);
				// 我不看棒子的东西,相关的都过滤
				if (txt.indexOf("韩剧") != -1 || txt.indexOf("韩语") != -1 || txt.indexOf("韩国") != -1)
					continue;
				Matcher titlemc = regex(txt,"<a href=\"([^<>]*forum\\.php\\?mod=viewthread&[amp;]*tid=[\\d]+)[^<>]+ class=\"xst\"[\\s]?>([^<]+)</a>"); // [color=red]正则部分替换测试时间2012-06-19可用[/color]
				Matcher timemc = regex(txt, "<em>([0-9|-]+)</em>"); // time
				System.out.print(i++ + "	");
				if (titlemc.find()) {
					String title = titlemc.group(2)
						.replaceAll("'", "''")
						.replaceAll("【", "[")
						.replaceAll("】", "]");
					System.out.print(title + "	"); // title

					String href = titlemc.group(1);

					String time = "";
					if (timemc.find()){
						time = timemc.group(1);
						Integer year = Integer.parseInt(time.substring(0,4));
						if(year!=null&&year<lastyear)continue;
						System.out.print(time+"	");	//日期
					}
					System.out.println(reurl(url, href));
				}
			}
		}
	}
	//URL链接拼接
	public static String reurl(String url,String href){
		String hrefurl = href;
		if(!href.toLowerCase().startsWith("http://")){
			hrefurl = url.substring(0,url.lastIndexOf("/") + 1) + href;
		}
		return hrefurl;
	}
	//简化正则表达式的使用
	public static Matcher regex(String htmltext, String regex) {
		Pattern spattern = null;
		Matcher smatcher = null;
		spattern = Pattern.compile(regex);
		smatcher = spattern.matcher(htmltext);
		return smatcher;
	}
	//抓取网页
	public static String gethtml(String htmltype,String httpurl){
		String str = "";
		try{
			URL urlx = new URL(httpurl);
			HttpURLConnection uc = (HttpURLConnection) urlx.openConnection();
			uc.setDoInput(true);
			uc.setUseCaches(false);
			uc.setRequestMethod("GET");
			uc.setInstanceFollowRedirects(true);
			uc.setConnectTimeout(30*1000);
			uc.setReadTimeout(60*1000);
			InputStream inputstream = uc.getInputStream();
			BufferedReader bufferedreader = null;
			if(htmltype==null||htmltype.trim().equals(""))bufferedreader = new BufferedReader(new InputStreamReader(inputstream));
			else bufferedreader = new BufferedReader(new InputStreamReader(inputstream,htmltype));
			String s1;
			while ((s1 = bufferedreader.readLine()) != null)
				str = str + s1;
		}catch (Exception e) {
			e.printStackTrace();
		}
		return str;
	}
}



分享到:
评论
2 楼 happysoul 2012-12-25  
2012-12-25
意外发现,网站换到suppig.net了~ b变p
代码懒得改了~
参考看就好了~
1 楼 happysoul 2012-06-19  
论坛帖子链接换成了全路径
正则已经修改
<a href=\"([^<>]*forum\\.php\\?mod=viewthread&[amp;]*tid=[\\d]+)[^<>]+ class=\"xst\"[\\s]?>([^<]+)</a>
通过[^<>]*来匹配 http://http://www.subpig.net/ 部分
附件没有修改
测试时间 2012-06-19

相关推荐

Global site tag (gtag.js) - Google Analytics