编者注:本文为历史博文归档;涉及 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     |  
 +-----------+          +-------------+

核心分层详解

框架主要划分为以下五个核心层次,各层职责明确,便于扩展与维护:

  1. 数据输入层 (Data Input)

    • 负责加载配置文件、数据库或其他外部数据源。
    • 示例文件包括 baiduindex/province.jsonbaiduindex/city.jsonbaiduindex/keywords.txt,用于为爬虫提供地域、城市及关键词等基础数据。
  2. 核心处理层 (Core Processing)

    • Spider 引擎:利用 OOSpider(或自定义引擎)进行任务调度与管理,涵盖并发控制与任务分配。
    • 任务管理:包括任务创建(如在 baiduIndexBuild 方法中构造请求列表)、执行(调用 spider.run())以及任务依赖管理。
    • 数据提取:支持通过注解(如 @ExtractBy)从网页或 API 返回的 JSON 数据中提取特定字段(如关键词、趋势平均值等)。
    • 网络请求:基于配置的 Site 信息(用户代理、请求头、Cookies 等)发起 HTTP 请求。
  3. 数据存储层 (Data Storage)

    • 支持将爬取数据持久化至文件系统(如通过 CsvFileModelPipeline 存储为 CSV 文件)或数据库系统中。
  4. 异常与日志处理 (Logging & Exceptions)

    • 日志记录:使用 LoggerFactory.getLogger 记录程序执行过程中的错误、警告等信息,便于调试与追踪。
    • 异常捕获:在文件读取、数据处理等环节捕获异常(如 IOException)并记录错误详情。
  5. 外部接口与工具 (External Tools)

    • 集成第三方工具库(如 json-utilsFileCopyUtilsStringUtils)辅助数据处理与文件操作。
    • 支持命令行接口(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 码界探秘 获取更多技术文章。

Java 码界探秘

博客地址:https://blog.jsdiff.com/

说明

  • 时效性提示:本文涉及的百度指数 API 接口结构及 Cookie 验证机制可能随官方策略调整而变更,代码中的 BDUSS Cookie 具有时效性,实际使用时请获取最新的有效凭证。
  • 依赖版本:代码依赖 WebMagic 及相关工具库(如 Guava、Apache Commons),具体版本兼容性请参考项目 pom.xml 或官方文档。