java多线程 开源项目_高拓展性的Java多线程爬虫框架reptile(个人开源项目)

Reptile是一个Java多线程爬虫框架,设计为高拓展性,支持单机和集群部署。它采用模块化设计,包括Scheduler、Downloader、ResponseHandler和Consumer四个核心组件,简化了爬虫开发流程。框架提供布隆过滤器进行去重处理,支持UserAgent和Proxy池,以及请求重试。默认使用ConsoleConsumer,但推荐使用MongoDBConsumer以利用其面向文档的存储特性。
摘要由CSDN通过智能技术生成

简介

Reptile是一个具有高拓展性的可支持单机与集群部署Java多线程爬虫框架,该框架可简化爬虫的开发流程。该框架各个组件高内聚松耦合的特性让用户可以对不同组件进行定制来满足不同的需求。

特性

模块化设计,具有高度拓展性

支持单机多线程部署

支持简单集群部署

配置简单清晰

支持同步或异步运行

单机部署时,请求爬取完毕并且无其他线程产生新请求时会自动停止爬虫并关闭所有可关闭的资源

整合Jsoup,支持HTML页面解析

请求调度器支持URL或请求的去重处理,提供布隆过滤器与集合等去重实现,默认使用布隆过滤器,可在配置类进行指定

支持设置UserAgent池与Proxy池,并且可设置请求对UserAgent与Proxy的选择策略,如随机或循环顺序选择

当爬取请求出现IO异常时,支持请求重试,可在配置类指定请求重试次数

架构

cacf986a9ea2

Reptile.png

Reptile作为爬虫主体可在主线程运行也可以异步运行,爬虫主要有四个核心组件:

Scheduler 执行请求调度,支持添加与拉取新的爬取请求,并支持去重处理

FIFOQueueScheduler 基于Java的ConcurrentLinkedQueue实现的先进先出无限队列调度器、线程安全、不支持持久化,适合作为小型爬虫的请求调度器

RedisFIFOQueueScheduler 基于Redis的列表实现的先进先出无限队列调度器、线程安全、阻塞添加与拉取请求、支持持久化,适合作为大型爬虫的请求调度器

Downloader 执行请求下载与解析响应

HttpClientDownloader基于apache的httpclient实现的下载器

ResponseHandler 由使用者提供实现来对响应处理,生成Result结果与新的爬取请求Request

Consumer 来对处理的结果Result进行消费,例如持久化存储,用户可自定义其具体实现

ConsoleConsumer 控制台数据消费者,默认使用System.out.println将数据输出到控制台

JsonFileConsumer Json文件消费者,将Result数据序列化为JSON字符串并按行输出到指定文件,这样读取数据时可直接按行反序列化JSON字符串

MongoDBConsumer MongoDB数据消费者,将Result数据存储到指定的MongoDB数据库中的表

四个组件之间的关系如架构图所示,它们之间的互相调用形成一个完整的工作流并在Workflow线程中运行,Reptile爬虫会根据配置的线程数量通过线程池创建指定数量的工作流线程并发执行工作流任务。

快速开始

使用Maven

clone项目并构建发布到本地仓库

git clone git@github.com:xiepuhuan/reptile.git

cd reptile

mvn -Dmaven.test.skip=true

在项目中使用Maven引入对应的依赖

com.xiepuhuan

reptile

0.3

使用方式

实现ResponseHandler接口,重写isSupport与handle方法。

isSupport方法根据reponseContext参数对象判断是否需要处理该响应,是则返回true,否则返回false。

handle方法处理该响应,并将处理结果存储到result,如果从响应中有提取到要爬取的新请求则将其作为返回值返回。

如果没有找到支持处理该响应的处理器则响应会被忽略。

实现Consumer接口,重写consume方法,执行对数据的消费,可在该方法中对响应处理结果进行持久化等操作,目前提供了ConsoleConsumer,JsonFileConsumer, MongoDBConsumer等实现,默认使用ConsoleConsumer。

推荐

推荐使用MongoDBConsumer作为爬虫消费者, 因为其面向文档存储, 文档可嵌套文档、数组, 并且预先不需要建表, 这些特性非常适合爬虫爬取的不确定网络数据, JSON格式数据的存储。

若是使用MongoDBConsumer作为数据消费者, 那么必须在ResponseHandler中的handle方法中调用result的setExtendedField方法并使用ResultExtendedField.MONGODB_DATABASE_COLLECTION_NAME常量作为键设置数据存储的表名称。

示例

单机部署

public class ZhihuPageHandler implements ResponseHandler {

private static final String[] URLS = new String[] {

"https://www.zhihu.com/api/v4/search_v3?t=general&q=java"

};

@Override

public List handle(Response response, Result result) {

Content content = response.getContent();

JSONObject jsonObject = JSON.parseObject(content.getContent(), JSONObject.class);

result.setResults(jsonObject.getInnerMap());

JSONObject paging = jsonObject.getJSONObject("paging");

if (!paging.getBoolean("is_end")) {

List requests = new ArrayList<>();

requests.add(new Request(paging.getString("next")));

return requests;

}

return null;

}

@Override

public boolean isSupport(Request request, Response response) {

return true;

}

public static void main(String[] args) {

// 构建Reptile爬虫配置类,

ReptileConfig config = ReptileConfig.Builder.cutom()

.setThreadCount(8)

.appendResponseHandlers(new ZhihuPageHandler())

.setDeploymentMode(DeploymentModeEnum.SINGLE)

.setConsumer(new ConsoleConsumer())

.build();

// 根据reptile配置构建Reptile爬虫并添加爬去的URL

Reptile reptile = Reptile.create(config).addUrls(URLS);

// 启动爬虫

reptile.start();

}

}

分布式部署

分布式部署时,创建配置类时需要通过setDeploymentMode方法指定部署模式为DeploymentModeEnum.Distributed,并且需要通过setScheduler方法设置一个Redis队列调度器,可以使用RedisFIFOQueueScheduler作为实现。

public class ZhihuPageHandler implements ResponseHandler {

private static final String[] URLS = new String[] {

"https://www.zhihu.com/api/v4/search_v3?t=general&q=java"

};

@Override

public List handle(Response response, Result result) {

Content content = response.getContent();

JSONObject jsonObject = JSON.parseObject(content.getContent(), JSONObject.class);

result.setResults(jsonObject.getInnerMap());

JSONObject paging = jsonObject.getJSONObject("paging");

if (!paging.getBoolean("is_end")) {

List requests = new ArrayList<>();

requests.add(new Request(paging.getString("next")));

return requests;

}

return null;

}

@Override

public boolean isSupport(Request request, Response response) {

return true;

}

public static void main(String[] args) {

// 构建Redis队列调度器

Scheduler scheduler = RedisFIFOQueueScheduler.Builder.custom()

.setRedisConfig(RedisConfig.DEFAULT_REDIS_CONFIG)

.setRequestFilter(RedisBloomRequestFilter.Builder.create())

.build();

// 构建数据消费者

Consumer consumer = new MongoDBConsumer(MongoDBConfig.DEFAULT_MONGODB_CONFIG);

// 构建Reptile爬虫配置类

ReptileConfig config = ReptileConfig.Builder.cutom()

.setThreadCount(8)

.appendResponseHandlers(new ZhihuPageHandler())

.setDeploymentMode(DeploymentModeEnum.Distributed)

.setScheduler(scheduler)

.setConsumer(consumer)

.build();

// 根据reptile配置构建Reptile爬虫并添加爬去的URL

Reptile reptile = Reptile.create(config).addUrls(URLS);

// 启动爬虫

reptile.start();

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值