使用线程池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;
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值