转载请注明出处:http://blog.csdn.net/xiaojimanman/article/details/46812645

http://www.llwjy.com/blogdetail/9df464b20cca5405c7ce07e2fb2d768f.html

个人博客站已经上线了,网址 www.llwjy.com
~欢迎各位吐槽~

-------------------------------------------------------------------------------------------------

在前面的几篇博客中,我们已经介绍了怎样採集纵横小说站点上的信息以及怎样把这些信息持久化到数据库中。如今我们就開始介绍怎样做分布式採集,让各个模块之间能够完美的配合。

採集类改动

在開始介绍分布式採集之前。我们须要对之前介绍的採集类加入一些方法。也就是返回上一篇博客中介绍的小说javabean,详细源代码还请參照个人站点上的博客源代码

1.简单介绍页

简单介绍页需呀加入一个方法,让它返回简单介绍页的数据信息,详细例如以下:

	/**
* @return
* @Author:lulei
* @Description: 分析简单介绍页。获取简单介绍页数据
*/
public NovelIntroModel getNovelIntro() {
NovelIntroModel bean = new NovelIntroModel();
bean.setMd5Id(ParseMD5.parseStrToMd5L32(this.pageUrl));
bean.setName(getName());
bean.setAuthor(getAuthor());
bean.setDescription(getDesc());
bean.setType(getType());
bean.setLastChapter(getLatestChapter());
bean.setChapterlisturl(getChapterListUrl());
bean.setWordCount(getWordCount());
bean.setKeyWords(keyWords());
return bean;
}

2.阅读页

阅读页内相同须要加入一个方法。让它返回阅读页内的数据信息,详细例如以下:

	/**
* @return
* @Author:lulei
* @Description: 分析阅读页。获取阅读页数据
*/
public NovelReadModel getNovelRead(){
NovelReadModel novel = new NovelReadModel();
novel.setTitle(getTitle());
novel.setWordCount(getWordCount());
novel.setContent(getContent());
return novel; }

这些方法都是对之前类中的方法做一个整合。将之前分析到的数据组装成一个javabean返回,方便后面的操作。

各页採集线程类

在实现分布式採集的时候,就须要编写各个页面的採集线程类。让他来控制各页面的採集业务。以下我们就一一介绍:

1.更新列表页线程

这个线程的主要功能就是监控更新列表页的数据。提取页面上的简单介绍页URL,觉得它们是有更新的页面,将相应的信息持久化到数据库中,详细实现例如以下:

 /**
*@Description: 更新列表页线程
*/
package com.lulei.crawl.novel.zongheng; import java.util.List;
import java.util.concurrent.TimeUnit; import com.lulei.db.novel.zongheng.ZonghengDb; public class UpdateListThread extends Thread{
private boolean flag = false;
private String url;//抓取的更新列表页URL
private int frequency;//採集频率 public UpdateListThread(String name, String url, int frequency){
super(name);
this.url = url;
this.frequency = frequency;
} @Override
public void run() {
flag = true;
ZonghengDb db = new ZonghengDb();
while (flag){
try {
UpdateList updateList = new UpdateList(url);
List<String> urls = updateList.getPageUrls(true);
db.saveInfoUrls(urls);
TimeUnit.SECONDS.sleep(frequency);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
super.run();
} public static void main(String[] args) {
// TODO Auto-generated method stub
UpdateListThread thread = new UpdateListThread("llist", "http://book.zongheng.com/store/c0/c0/b9/u0/p1/v0/s9/t0/ALL.html", 60);
thread.start(); } }

2.简单介绍页&章节列表页线程类

因为一个简单介绍页就相应一个章节列表页,所以我们就把这两个线程合为一个线程,让事实上现小说简单介绍信息的採集以及小说章节列表信息的採集,详细实现例如以下:

 /**
*@Description: 小说简单介绍信息线程
*/
package com.lulei.crawl.novel.zongheng; import java.util.List;
import java.util.concurrent.TimeUnit; import com.lulei.crawl.novel.zongheng.model.NovelIntroModel;
import com.lulei.db.novel.zongheng.ZonghengDb; public class IntroPageThread extends Thread {
private boolean flag = false; public IntroPageThread(String name) {
super(name);
} @Override
public void run() {
flag = true;
try {
ZonghengDb db = new ZonghengDb();
while (flag) {
//随机获取一个待採集的简单介绍页url
String url = db.getRandIntroPageUrl(1);
if (url != null) {
IntroPage intro = new IntroPage(url);
NovelIntroModel bean = intro.getNovelIntro();
//採集小说章节列表页信息
ChapterPage chapterPage = new ChapterPage(bean.getChapterlisturl());
List<String[]> chapters = chapterPage.getChaptersInfo();
bean.setChapterCount(chapters == null ? 0 : chapters.size());
//更新小说简单介绍信息
db.updateInfo(bean);
//插入待採集的章节列表
db.saveChapters(chapters);
//假设本次有待採集的资源。睡眠一个时间。没有待採集的资源。睡眠还有一个时间
TimeUnit.MILLISECONDS.sleep(500);
}else {
TimeUnit.MILLISECONDS.sleep(1000);
}
}
} catch (Exception e) {
e.printStackTrace();
}
} public static void main(String[] args) {
// TODO Auto-generated method stub
IntroPageThread thread = new IntroPageThread("novelinfo");
thread.start();
} }

3.阅读页线程

这个线程的主要功能就是将小说阅读页的信息採集并持久化到数据库中。详细例如以下:

 /**
*@Description: 小说阅读页线程
*/
package com.lulei.crawl.novel.zongheng; import java.util.concurrent.TimeUnit; import com.lulei.crawl.novel.zongheng.model.NovelChapterModel;
import com.lulei.crawl.novel.zongheng.model.NovelReadModel;
import com.lulei.db.novel.zongheng.ZonghengDb;
import com.lulei.util.ParseMD5; public class ReadPageThread extends Thread {
private boolean flag = false;
public ReadPageThread(String name) {
super(name);
} @Override
public void run() {
flag = true;
ZonghengDb db = new ZonghengDb();
while (flag) {
try {
//随机获取待採集的阅读页
NovelChapterModel chapter = db.getRandReadPageUrl(1);
if (chapter != null) {
ReadPage read = new ReadPage(chapter.getUrl());
NovelReadModel novel = read.getNovelRead();
if (novel == null) {
continue;
}
novel.setChapterId(chapter.getChapterId());
novel.setTime(chapter.getTime());
novel.setUrl(chapter.getUrl());
//保存阅读页信息
db.saveNovelRead(novel);
//将状态改动为不须要採集
db.updateChapterState(ParseMD5.parseStrToMd5L32(novel.getUrl()), 0);
//假设本次有待採集的资源,睡眠一个时间,没有待採集的资源,睡眠还有一个时间
TimeUnit.MILLISECONDS.sleep(500);
} else {
TimeUnit.MILLISECONDS.sleep(1000);
}
} catch(Exception e){
e.printStackTrace();
}
}
} public static void main(String[] args) {
ReadPageThread thread = new ReadPageThread("novel read page");
thread.start();
} }

分布式採集

上面已经介绍完了各个线程完毕的工作,以下就须要一个类来控制管理这些线程。让其执行起来,详细代码例如以下:

 /**
*@Description:
*/
package com.lulei.crawl.novel.zongheng; import java.util.List; import com.lulei.crawl.novel.zongheng.model.CrawlListInfo;
import com.lulei.db.novel.zongheng.ZonghengDb; public class CrawStart {
private static boolean booleanCrawlList = false;
private static boolean booleanCrawlIntro = false;
//简单介绍页採集线程数目
private static int crawlIntroThreadNum = 2;
private static boolean booleanCrawlRead = false;
//阅读页採集线程数目
private static int crawlReadThreadNum = 10; /**
* @Author:lulei
* @Description: 更新列表页採集
*/
public void startCrawlList(){
if (booleanCrawlList) {
return;
}
booleanCrawlList = true;
ZonghengDb db = new ZonghengDb();
List<CrawlListInfo> infos = db.getCrawlListInfos();
if (infos == null) {
return;
}
for (CrawlListInfo info : infos) {
if (info.getUrl() == null || "".equals(info.getUrl())) {
continue;
}
UpdateListThread thread = new UpdateListThread(info.getInfo(), info.getUrl(), info.getFrequency());
thread.start();
}
} /**
* @Author:lulei
* @Description: 小说简单介绍页和章节列表页
*/
public void startCrawlIntro() {
if (booleanCrawlIntro) {
return;
}
booleanCrawlIntro = true;
for (int i = 0; i < crawlIntroThreadNum; i++) {
IntroPageThread thread = new IntroPageThread("novel info thread" + i);
thread.start();
}
} /**
* @Author:lulei
* @Description: 小说阅读页
*/
public void startCrawlRead() {
if (booleanCrawlRead) {
return;
}
booleanCrawlRead = true;
for (int i = 0; i < crawlReadThreadNum; i++) {
ReadPageThread thread = new ReadPageThread("novel read page" + i);
thread.start();
}
} public static void main(String[] args) {
CrawStart start = new CrawStart();
start.startCrawlList();
start.startCrawlIntro();
start.startCrawlRead();
} }

执行结果

通过上面的这几个步骤,纵横小说的分布式採集程序已经完毕,以下就为大家展示一下採集后的数据库截图

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

写在最后

在上面的线程实现中,有非常多的配置信息,比方说线程中的两个请求之间的间隔时间以及各类线程的数量,像这些信息我们都能够将其写到配置文件里,方便之后的改动(这里写到程序中是方便大家的理解,还请见谅)。

----------------------------------------------------------------------------------------------------

ps:近期发现其它站点可能会对博客转载,上面并没有源链接,如想查看很多其它关于 基于lucene的案例开发点击这里。或訪问网址http://blog.csdn.net/xiaojimanman/article/category/2841877
或 http://www.llwjy.com/blogtype/lucene.html

-------------------------------------------------------------------------------------------------

小福利

-------------------------------------------------------------------------------------------------

      个人在极客学院上《Lucene案例开发》课程已经上线了(眼下上线到第二课)。欢迎大家吐槽~

第一课:Lucene概述

第二课:Lucene 经常使用功能介绍

基于lucene的案例开发:纵横小说分布式採集的更多相关文章

  1. 基于lucene的案例开发:查询语句创建PackQuery

    转载请注明出处:http://blog.csdn.net/xiaojimanman/article/details/44656141 http://www.llwjy.com/blogdetail/1 ...

  2. 基于zookeeper和强一致性复制实现MySQL分布式数据库集群

    http://qikan.cqvip.com/article/detail.aspx?id=667750898&from=zk_search

  3. 基于AgileEAS.NET企业应用开发平台的分布式解决方案

    开篇 分布式应用 AgileEAS.NET基于Microsoft .Net构件技术而构建,Microsoft .Net最吸引人的莫过于分布式应用技术,基已经提供了XML WebService. .Ne ...

  4. Apache Solr采用Java开发、基于Lucene的全文搜索服务器

    http://docs.spring.io/spring-data/solr/ 首先介绍一下solr: Apache Solr (读音: SOLer) 是一个开源.高性能.采用Java开发.基于Luc ...

  5. 基于JWT的Token开发案例

    代码地址如下:http://www.demodashi.com/demo/12531.html 0.准备工作 0-1运行环境 jdk1.8 maven 一个能支持以上两者的代码编辑器,作者使用的是ID ...

  6. [.NET领域驱动设计实战系列]专题八:DDD案例:网上书店分布式消息队列和分布式缓存的实现

    一.引言 在上一专题中,商家发货和用户确认收货功能引入了消息队列来实现的,引入消息队列的好处可以保证消息的顺序处理,并且具有良好的可扩展性.但是上一专题消息队列是基于内存中队列对象来实现,这样实现有一 ...

  7. 8 个基于 Lucene 的开源搜索引擎推荐

    Lucene是一种功能强大且被广泛使用的搜索引擎,以下列出了8种基于Lucene的搜索引擎,你可以想象它们有多么强大. 1. Apache Solr Solr 是一个高性能,采用Java5开发,基于L ...

  8. WebGIS中兴趣点简单查询、基于Lucene分词查询的设计和实现

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.前言 兴趣点查询是指:输入框中输入地名.人名等查询信息后,地图上可 ...

  9. Lucene/Solr搜索引擎开发笔记 - 第1章 Solr安装与部署(Jetty篇)

    一.为何开博客写<Lucene/Solr搜索引擎开发笔记> 本人毕业于2011年,2011-2014的三年时间里,在深圳前50强企业工作,从事工业控制领域的机器视觉方向,主要使用语言为C/ ...

随机推荐

  1. 彻底弄懂px em rem

    国内的设计师大都喜欢用px,而国外的网站大都喜欢用em和rem,那么三者有什么区别,又各自有什么优劣呢? PX特点 1. IE无法调整那些使用px作为单位的字体大小: 2. 国外的大部分网站能够调整的 ...

  2. BPM控制控件的隐藏与显示

    在BPM官方给的属性中控件属性DisplayRule中设置条件控制显示或者隐藏的时候,只能控制选中的,标题也要重新设置,这样就比较麻烦,不如自己来写javascript代码. 举一个简单的例子: 通过 ...

  3. BZOJ 3992 DP+NTT+快速幂

    思路: 普通的DP很好想吧 f[i][j]+=f[i-1][j*s[k]]  前i个数  mod m=j 的个数 m是质数  模数是质数  这就很有趣了 那么我们就求出来原根  所有的数都取指数 搞出 ...

  4. (转载) 小议TCP的MSS(最大分段)以及MTU(最大传输单元)

    [背景知识]  MTU: Maximum Transmission Unit 最大传输单元 MSS: Maximum Segment Size 最大分段大小PPPoE: PPP Over Ethern ...

  5. C#解除某类警告。。。。。。。。。。

    C#预处理器指令取消不必要的警告 今天将自己写的一个类库生成一个DLL后,想把注释也加进去.... 方法:在属性->生成选项卡->XML文档文件(勾选)(生成的文件名不能修改,使用时必须跟 ...

  6. MD5三种方法的学习总结

    MD5百度百科 MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致.是计算机广泛使用的杂凑算法之一(又译摘要算法.哈希算法),主流编程语言普遍已 ...

  7. 洛谷P2851 [USACO06DEC]最少的硬币The Fewest Coins(完全背包+多重背包)

    题目描述 Farmer John has gone to town to buy some farm supplies. Being a very efficient man, he always p ...

  8. C# 时间日期(函数,解释)

    C#时间/日期格式大全,C#时间/日期函数大全 有时候我们要对时间进行转换,达到不同的显示效果 默认格式为:2005-6-6 14:33:34 如果要换成成200506,06-2005,2005-6- ...

  9. 目标跟踪ObjectT综述介绍

    此文也很详细:http://blog.csdn.net/maochongsandai110/article/details/11530045 原文链接:http://blog.csdn.net/pp5 ...

  10. Javaee 内部引用

    1.final修饰类,修饰方法,修饰变量有什么特点? final修饰的类不能被继承太监类,可以被继承使用但不能修改,如果父类没有final修饰的方法子类可以添加上,成员变量需要在建类前被赋值且不能改动 ...