怎么使用Java实现一个爬虫框架
编者注:本文为历史博文归档;涉及 JDK、框架与工具链版本请以当前官方文档为准。引用外链图片可能失效,阅读时请注意时效性。
项目简介:crawler-mouse
crawler-mouse 是一个基于 Java 实现的轻量级爬虫框架。该框架旨在简化网络数据采集流程,提供从任务配置、核心调度到数据持久化的完整解决方案。
架构设计
框架整体采用分层架构设计,主要包含数据输入、核心处理、数据存储以及辅助模块(日志与异常处理)。以下是架构流程示意图:
+---------------------+
| Data Input |
| -------------------- |
| Config Files (JSON, |
| TXT) & Resources |
+--------+-------------+
|
v
+-----------------------+
| Core Processing |
| ---------------------|
| Spider Engine |
| - Task Management |
| - Data Extraction |
| - HTTP Requests |
| (Using Site Config) |
+-----+--------+--------+
|
v
+-----------------------+
| Data Storage |
| ---------------------|
| File System (CSV) |
| (Or Databases) |
+-------------+---------+
|
+------------------------+------+
| |
+------+-----+ +-----+------+
| Logging | | Exceptions |
| -------- | | ---------- |
| Logger | | Handler |
+-----------+ +-------------+核心分层详解
框架主要划分为以下五个核心层次,各层职责明确,便于扩展与维护:
数据输入层 (Data Input)
- 负责加载配置文件、数据库或其他外部数据源。
- 示例文件包括
baiduindex/province.json、baiduindex/city.json和baiduindex/keywords.txt,用于为爬虫提供地域、城市及关键词等基础数据。
核心处理层 (Core Processing)
- Spider 引擎:利用
OOSpider(或自定义引擎)进行任务调度与管理,涵盖并发控制与任务分配。 - 任务管理:包括任务创建(如在
baiduIndexBuild方法中构造请求列表)、执行(调用spider.run())以及任务依赖管理。 - 数据提取:支持通过注解(如
@ExtractBy)从网页或 API 返回的 JSON 数据中提取特定字段(如关键词、趋势平均值等)。 - 网络请求:基于配置的
Site信息(用户代理、请求头、Cookies 等)发起 HTTP 请求。
- Spider 引擎:利用
数据存储层 (Data Storage)
- 支持将爬取数据持久化至文件系统(如通过
CsvFileModelPipeline存储为 CSV 文件)或数据库系统中。
- 支持将爬取数据持久化至文件系统(如通过
异常与日志处理 (Logging & Exceptions)
- 日志记录:使用
LoggerFactory.getLogger记录程序执行过程中的错误、警告等信息,便于调试与追踪。 - 异常捕获:在文件读取、数据处理等环节捕获异常(如
IOException)并记录错误详情。
- 日志记录:使用
外部接口与工具 (External Tools)
- 集成第三方工具库(如
json-utils、FileCopyUtils、StringUtils)辅助数据处理与文件操作。 - 支持命令行接口(CLI),可通过
main方法直接启动爬虫任务。
- 集成第三方工具库(如
实战案例:爬取百度指数
以下代码展示了如何使用该框架配置并执行百度指数的爬取任务。代码中使用了注解式配置来定义目标 URL 和数据提取规则。
/**
* @author daichangya@163.com
*/
@TargetUrl("http://index.baidu.com/api/SearchApi/index.*")
public class BaiduIndexModel {
private static Logger logger = LoggerFactory.getLogger(BaiduIndexModel.class);
private static Site site = Site.me().setDomain("index.baidu.com").setSleepTime(1000)
.addCookie("BDUSS",
"kJ4SEYtT05PM2U4NlVPQWY2dWNZRjNmMng1ZkI5TkVSclRWd3g5VmZaeWdlbjVmSVFBQUFBJCQAAAAAAAAAAAEAAAAQTRyIwfXP~rz8cQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKDtVl-g7VZfZ").
setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31");
@ExtractBy(value = "status", type = ExtractBy.Type.JsonPath)
private String status;
@ExtractBy(value = "data.userIndexes[0].word[0].name", type = ExtractBy.Type.JsonPath)
private String keyWord;
@ExtractBy(value = "data.generalRatio[0].all.avg", type = ExtractBy.Type.JsonPath)
private String all;
@ExtractBy(value = "data.generalRatio[0].wise.avg", type = ExtractBy.Type.JsonPath)
private String wise;
@ExtractBy(value = "data.generalRatio[0].pc.avg", type = ExtractBy.Type.JsonPath)
private String pc;
@ExtractByUrl("areaName=(.*)")
private String areaName;
public static void main(String[] args) {
Spider spider = baiduIndexBuild(null);
spider.run();
}
public static Spider baiduIndexBuild(String cookie) {
List<Request> urlList = Lists.newArrayList();
String urlTemp = "http://index.baidu.com/api/SearchApi/index?area={}&word=[[%7b%22name%22:%22{}%22,%22wordType%22:1%7d]]&days=7&areaName={}";
Resource provinceRes = new ClassPathResource("baiduindex/province.json");
String jsonStr = null;
try {
jsonStr = new String(FileCopyUtils.copyToByteArray(provinceRes.getInputStream()));
Map<String, String> provinceMap = JsonUtils.toObject(jsonStr, Map.class);
Resource cityRes = new ClassPathResource("baiduindex/city.json");
String cityStr = new String(FileCopyUtils.copyToByteArray(cityRes.getInputStream()));
Map<String, String> cityMap = JsonUtils.toObject(cityStr, Map.class);
provinceMap.putAll(cityMap);
Resource keyWordRes = new ClassPathResource("baiduindex/keywords.txt");
String[] keyWords = new String(FileCopyUtils.copyToByteArray(keyWordRes.getInputStream())).split("\n");
for (int i = 0; i < keyWords.length; i++) {
for (String key : provinceMap.keySet()) {
String url = StringUtils.stringFormat(urlTemp, provinceMap.get(key), keyWords[i], key);
Request request = new Request(url);
request.putExtra(Request.DEL_KEY_WORD, keyWords[i]);
urlList.add(request);
}
}
} catch (IOException e) {
logger.error("baiduIndexBuild error", e);
}
if(org.apache.commons.lang3.StringUtils.isNotBlank(cookie)){
site.addCookie("BDUSS",cookie);
}
Filters filters = new Filters();
filters.addFilters(Lists.newArrayList(new FilterKeyWordRequest()));
Spider spider = OOSpider.create(site
, new CsvFileModelPipeline(), BaiduIndexModel.class).addRequest(urlList.toArray(new Request[0])).thread(1)
.setFilters(filters);
return spider;
}
}更多资源
欢迎关注微信公众号 Java 码界探秘 获取更多技术文章。

说明
- 时效性提示:本文涉及的百度指数 API 接口结构及 Cookie 验证机制可能随官方策略调整而变更,代码中的
BDUSSCookie 具有时效性,实际使用时请获取最新的有效凭证。 - 依赖版本:代码依赖 WebMagic 及相关工具库(如 Guava、Apache Commons),具体版本兼容性请参考项目
pom.xml或官方文档。
版权声明:本文为原创文章,版权归 戴老师的博客 所有,转载请联系博主获得授权。
本文地址:https://1diff.fun/archives/zen-me-shi-yong-java-shi-xian-yi-ge-pa-chong-kuang-jia.html
如果对本文有什么问题或疑问都可以在评论区留言,我看到后会尽量解答。