转载请注明出处: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. 基于Websocket的火拼俄罗斯(基础)

    传统的HTTP请求是由浏览器发起,然后呢服务端接收到请求之后呢返回一个数据.那么这样一次来回之后呢请求就断了.但是WebSocket它不一样,它同样是由浏览器去发起一个请求但是这个请求是一个WebSo ...

  2. hihoCoder-1633 ACM-ICPC北京赛区2017 G.Liaoning Ship’s Voyage 线段与三角形规范相交

    题面 题意:给你一个20*20的地图,起点(0,0),终点(n-1,n-1),有障碍的点为‘#’,每次可以向8个方向走一步,还给了一个三角形,除了障碍以外,到这8个方向上的点的线段如果没有与三角形相交 ...

  3. SwiftUI 官方教程(二)

    SwiftUI 官方教程(二) 2. 自定义 Text View 为了自定义 view 的显示,我们可以自己更改代码,或者使用 inspector 来帮助我们编写代码. 在构建 Landmarks 的 ...

  4. 深入了解Token认证的来龙去脉

    Token 是在服务端产生的,如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端.前端可以在每次请求的时候带上 Token 证明自己的合法地位.   不久 ...

  5. NOIP2011 D1T1 铺地毯

    P1692 铺地毯 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 NOIP2011 day1 第一题 描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩 ...

  6. 3) 十分钟学会android--建立第一个APP,建立简单的用户界面

    在本小节里,我们将学习如何用 XML 创建一个带有文本输入框和按钮的界面.下一节课将学会使 APP 对按钮做出响应——按钮被按下时,文本框里的内容被发送到另外一个 Activity. Android ...

  7. css3的过滤效果

    上面的图片就是css3新特性的滤镜效果,学会了这些那么我们这群爱美爱帅的大web是不是就可以完美的用代码实现照片美化了捏~~ 好,咱们先把照片后面的白框实现, <style> #div1{ ...

  8. (转)基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍

    http://www.cnblogs.com/wuhuacong/p/3281103.html 最近花了很多时间在重构和进一步提炼Winform开发框架的工作上,加上时不时有一些项目的开发工作,我博客 ...

  9. 【转】Oracle基础结构认知—进程及逻辑结构 礼记八目 2017-12-17 19:33:21

    原文地址:https://www.toutiao.com/i6500477672349499917/ 一. Process Structure进程结构 Oracle有两种类型的进程: 服务器进程和后台 ...

  10. Smallest Common Multiple FreeCodeCamp

    题目:找出能被两个给定参数和它们之间的连续数字整除的最小公倍数.  范围是两个数字构成的数组,两个数字不一定按数字顺序排序. 分析:首先题目的意思求一个连续数列的所有数字的最小公倍数,这连续的数字序列 ...