最近在看java多线程,多看不如一敲,索性就爬取一些数据量较大的信息吧.
题目大意:在取360网页手机助手里面抓取某类软件的前几十个排名的软件的全部评论.
例如:获取数据的xml格式如下:
<?xml version="1.0"?>
<app>
<appid>优酷</appid>
<allcomments>53268</allcomments>
<comment>
<userid>西雅尔</userid>
<time>2015-10-06</time>
<review>为什么流量缓存不了</review>
<agreecount>10</agreecount>
</comment>
<comment>
<userid>嘿明天</userid>
<time>2015-10-09</time>
<review>很好用,值得推荐</review>
<agreecount>2</agreecount>
</comment>
</app>
分析:
1.分析:对于每一个软件其url地址,
如优酷http://zhushou.360.cn/detail/index/soft_id/3581只是其最后的数字不同(我们下文就叫他”id号”),关键就是获得其id号就ok了.
解决:在某种类型的网页里,我们可以利用正则,Jsoup等获取其id号
2.分析:其评论是动态加载,利用分析者工具发现其每次访问地址如http://intf.baike.360.cn/index.php?name=%E4%BC%98%E9%85%B7%E8%A7%86%E9%A2%91&c=message&a=getmessage&start=10&count=10,其中name是软件的名字,start是评论这次从哪里开始,count是这一次显示多少个,我的这里每次最多显示20个,这三个是动态变化的.我们只要获得name,在设置一下start,count的变化规则就ok了.
解决:在访问每个软件时,在其网页里面能获得.
3.分析:比如酷狗其评论就8万多,而每次只能抓取20个,这要用多长时间啊,我刚开始用单线程,哎呀,慢的我想哭!
解决:多线程这时间就派上用场了!
代码:
分析完了,想通了,就开始写代码吧.当然在其中还是会出现这样那样的错误,不怕,解决他就ok了.
具体代码请参考我的git
遇见的问题:
把xml写不进去文件,但是明明在终端下能把抓取到的信息输出来.
相关代码:
for(int start = 0;start < allcommentscount;start += count){
if(start+count>allcommentscount){
count = allcommentscount-start;
}
executorService.submit(new CrawlComments(app, start, count, name));
}
executorService.shutdown();
CrawlUtil.WtiteXmlToFile(app, "/home/xxxx/comments/" + name.split("\\+")[0] + ".xml");
在写线程池的时候,只是照猫画虎的使用,没有真正的理解executorService.shutdown();
也就是说他只是停止接受任务,我还没有待任务完成就执行了写文件的操作,当然什么都不会有.
改正后的代码:
for(int start = 0;start < allcommentscount;start += count){
if(start+count>allcommentscount){
count = allcommentscount-start;
}
executorService.submit(new CrawlComments(app, start, count, name));
}
executorService.shutdown();
//检查任务是否执行完成
while (!executorService.isTerminated()) {
Thread.sleep(1000);
}
CrawlUtil.WtiteXmlToFile(app, "/home/xxxx/comments/" + name.split("\\+")[0] + ".xml");