- 该项目是一个基于 Java 的通用爬虫系统,专注于从不同网站抓取数据,核心设计理念是提供灵活、可扩展的爬虫框架,同时保证系统的稳定性和高效性。
- 项目不包含 Job 调度相关内容,需通过外部触发,可兼容所有 Job 调度框架(如 Quartz、XXL-Job 等)。
- 核心目标:简化爬虫开发流程,将其拆解为下载与数据处理两大核心阶段。通过封装下载阶段的技术细节(如请求管理、动态渲染、资源控制等),让开发者聚焦于数据处理;同时,在数据处理阶段引入 AI 编码工具或大模型能力,简化非结构化数据到结构化数据的解析流程,最终实现爬虫的高效开发与快速迭代。
- 痛点问题:https://blog.csdn.net/m0_46569883/article/details/149530711
项目采用模块化设计,主要分为两个核心子模块:
模块名称 | 功能描述 |
---|---|
crawler-core |
包含爬虫核心功能,如静态资源爬取处理器、无头浏览器爬取处理器、爬虫配置、重试机制、统一调度等。 |
crawler-example |
提供具体的爬虫实现示例(如百度百科、腾讯视频排行榜爬虫),展示如何基于 crawler-core 开发实际爬虫任务。 |
-
资源控制:通过
PlaywrightManager
类管理浏览器实例,基于配置的maxCount
控制最大浏览器实例和页面数量,避免资源耗尽。 -
并发控制:使用
Semaphore
信号量限制并发页面创建数量,确保系统资源稳定。 -
资源复用:维护页面对象队列,复用已有页面对象,减少重复创建销毁的开销。
-
自动销毁:通过destroy()方法在系统关闭时自动关闭浏览器实例和 Playwright 资源,避免内存泄漏。
// PlaywrightManager 核心资源管理逻辑 @Override public void destroy() { log.info("Closing browser."); if (browserContexts != null && !browserContexts.isEmpty()) { browserContexts.forEach(browserContext -> { browserContext.close(); Browser browser = browserMap.remove(browserContext); if (browser != null) browser.close(); Playwright playwright = playwrightMap.remove(browserContext); if (playwright != null) playwright.close(); }); } }
-
基于
RestTemplate
处理 HTTP 请求,结合 Apache HttpClient 实现可配置的 HTTP 连接池。 -
支持代理配置,灵活应对目标网站的反爬策略。
-
提供便捷的请求方法(如postTextPlain),简化请求构造流程。
// HttpManager 中的 POST 请求示例 public <T> T postTextPlain(String url, String text, Class<T> responseType) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); HttpEntity<String> entity = new HttpEntity<>(text, headers); ResponseEntity<T> response = restTemplate.exchange(url, HttpMethod.POST, entity, responseType); return response.getBody(); }
- 通过配置文件设定线程池参数(核心线程数、最大线程数、任务队列容量),高效处理并发任务。
- 示例配置:核心线程数 60、最大线程数 120、队列容量 1000,平衡性能与资源占用。
-
核心接口
CrawlerProcessor<I, O, R>
采用泛型设计,支持灵活定义输入(I)、页面输出(O)、最终结果(R)类型,适配不同爬虫场景:
- 输入参数类型(I):可为 URL、请求体等任意类型
- 页面输出类型(O):可为 HTTP 响应、HTML 文档、JSON 数据等
- 最终结果类型(R):可为处理后的列表、对象等数据结构
-
提供抽象实现类(如
DefaultAbsPlayWrightProcessor
、DefaultAbsJsoupProcessor
),封装通用逻辑(如下载、重试、资源回收),减少重复开发。// 泛型爬虫处理器接口定义 public abstract class DefaultAbsPlayWrightProcessor<I, R> extends AbsCrawlerProcessor<I, Page, R> { @Override public Page download(CrawlerContext<I, Page> context) { // 页面下载通用逻辑(获取页面、导航、等待加载) } @Override public abstract R process(CrawlerContext<I, Page> context); // 留给子类实现具体解析逻辑 }
- 参数构造:通过
addCrawlerContext()
初始化单个任务上下文,addAllCrawlerContext()
支持批量任务初始化。 - 页面下载:
download()
方法负责获取页面内容(支持 Playwright 动态页面或 Jsoup 静态页面)。 - 结果处理:
process()
方法解析页面内容,提取目标数据。 - 钩子方法:
before()
和after()
支持任务执行前后的日志记录、资源清理等操作(如after()
中回收 Playwright 页面)。
-
内置重试逻辑,可通过
retryExceptions()
定义需要重试的异常类型(如
TimeoutError
、CrawlerRetryException
)。// 重试异常定义示例 @Override public List<Class<? extends Exception>> retryExceptions() { return Stream.of(TimeoutError.class, CrawlerRetryException.class).collect(Collectors.toList()); }
-
支持配置最大重试次数和重试间隔,应对网络波动等临时性错误。
-
通过
CrawlerService
类管理所有爬虫任务,提供fetch
(单个任务)、fetchBatch
(批量任务)等方法,简化调用流程。/** * 同一类型 批量 爬取 数据 */ @SuppressWarnings("unchecked") public <I, O, R> List<R> fetchBatch(String code) { AbsCrawlerProcessor<I, O, R> processor = (AbsCrawlerProcessor<I, O, R>) crawlerProcessorMap.get(code); if (processor != null) { return processor.executeBatch(); } else { throw new CrawlerException("No processor found for code: " + code); } }
-
支持多种调度方式:顺序调度、批量调度、总分调度(先访问一个 URL,再处理批量衍生 URL)。
- 通过
CrawlerEnum
集中管理爬虫配置(编码、名称、URL、实现类、排序),方便切换和维护。 - 支持扩展为数据库存储,实现动态管理爬虫任务。
-
页面操作工具:
PageUtils
提供页面滚动(scrollPageToBottom)、弹窗处理(handleDialogs)等功能,适配动态页面交互需求。// 滚动页面到底部(间隔 300 毫秒) public static void scrollPageToBottom(Page page) { page.evaluate("() => {\n" + " return new Promise((resolve, reject) => {\n" + " const totalHeight = document.documentElement.scrollHeight;\n" + " let distance = 500;\n" + " let lastScrollY = 0;\n" + " let noChangeCount = 0;\n" + " const maxNoChangeCount = 5; // 设置最大连续无变化次数\n" + " let timer = setInterval(() => {\n" + " window.scrollBy(0, distance);\n" + " let currentScrollY = window.scrollY;\n" + " if (currentScrollY === lastScrollY) {\n" + " noChangeCount++;\n" + " if (noChangeCount >= maxNoChangeCount) {\n" + " clearInterval(timer);\n" + " resolve();\n" + " }\n" + " } else {\n" + " noChangeCount = 0;\n" + " }\n" + " lastScrollY = currentScrollY;\n" + " }, 300);\n" + " });\n" + "}"); }
-
通用工具:
CommonUtils
提供随机休眠(randomSleep
)等功能,模拟人工操作间隔,降低反爬风险。
-
通过CrawlerProperties集中管理框架配置,支持代理、HTTP 连接池、线程池、重试策略等参数的灵活配置:
@Component @ConfigurationProperties(prefix = "crawler") @Data public class CrawlerProperties { private Proxy proxy; // 代理配置 private Http http; // HTTP连接池配置 private Thread thread; // 线程池配置 private int maxRetries; // 最大重试次数 private long retryDelayMs; // 重试间隔(毫秒) private int batchTimeoutSeconds; // 批量超时时间(秒) private int timeoutSeconds; // 单个请求超时时间(秒) }
-
功能:抓取百度百科页面的基本信息(如概述、ID、剧情介绍等)。
-
关键实现:通过 XPath 选择器提取页面元素,处理文本清洗(如去除引用标记)。
@Override public Map<String,String> process(CrawlerContext<String, Page> context) { Page page = context.getOutput(); List<ElementHandle> itemNameElements = page.querySelectorAll("xpath=//dt[contains(@class, 'itemName_')]"); List<ElementHandle> itemValueElements = page.querySelectorAll("xpath=//dd[contains(@class, 'itemValue_')]"); Map<String, String> itemMap = new HashMap<>(); for (int i = 0; i < itemNameElements.size(); i++) { String itemName = itemNameElements.get(i).innerText(); String itemValue = itemValueElements.get(i).innerText().replaceAll("\\[\\d+]", "").trim(); itemMap.put(itemName, itemValue); } // 提取ID和概要信息 ElementHandle element = page.querySelector("#J-vars"); itemMap.put("summary", this.getSummary(page)); itemMap.put("id", element.getAttribute("data-lemmaid")); return itemMap; }
- 功能:抓取腾讯视频儿童频道排行榜数据(排名、名称、URL)。
- 关键实现:通过 CSS 选择器定位列表项,提取排名和内容信息。
- 模块化与低耦合
核心功能与示例分离,
crawler-core
提供通用能力,crawler-example
展示具体实现,便于维护和扩展。 - 资源高效利用 Playwright 资源池通过复用页面对象和信号量控制,减少浏览器实例创建销毁的开销,降低系统资源占用。
- 灵活性与通用性 泛型设计适配不同数据类型,支持动态页面(Playwright)和静态页面(Jsoup),可应对多种网站结构。
- 稳定性保障 重试机制、线程池控制、资源自动回收等设计,确保系统在高并发或网络不稳定时的可靠性。
- 易扩展性 统一接口和抽象类简化新爬虫的开发,扩展点支持未来通过配置或脚本扩展功能,无需修改核心代码。
- JDK 版本:8(通过项目配置
languageLevel="JDK_1.8"
确认) - 依赖管理:Maven(项目包含 pom.xml 配置)
- Playwright 浏览器:需提前安装(框架自动管理实例,支持无头模式),配置文件指定谷歌浏览器路径也可
- 继承抽象类:根据页面类型选择继承
DefaultAbsPlayWrightProcessor
(动态页面)或DefaultAbsJsoupProcessor
(静态页面)。 - 实现核心方法:
process()
:定义页面解析逻辑,提取目标数据。addCrawlerContext()
:初始化爬虫任务参数(如 URL)。
- 配置调度:通过
CrawlerService
调用fetch
或fetchBatch
方法执行任务。
- 页面解析逻辑通过ai 将页面非结构化解析为结构化数据
- 完善测试用例与部署方案。
-
用途限制与法律合规提示 本开源爬虫框架(以下简称 “框架”)的开发与发布,仅为技术研究、合法数据获取及学习交流提供工具支持。 使用者承诺,在使用本框架时,将严格遵守中华人民共和国及相关 jurisdictions 的法律法规,包括但不限于《中华人民共和国网络安全法》《中华人民共和国数据安全法》《中华人民共和国个人信息保护法》《互联网信息服务管理办法》等,同时遵守目标网站的 robots 协议、服务条款及数据使用规则。
-
禁止非法使用 严禁任何主体利用本框架从事以下行为(包括但不限于): 未经许可爬取、获取、存储、传播受法律保护的商业秘密、个人信息、隐私数据或其他专有数据; 对目标网站进行恶意爬虫(如高频请求导致服务器负载过高、规避反爬机制进行非法数据抓取等); 侵犯他人知识产权、名誉权、肖像权等合法权益; 用于任何违法犯罪活动或违反公序良俗的行为。
-
免责声明 本框架的开发者及贡献者(以下简称 “开发者”)仅对框架的技术功能完整性负责,不对使用者的具体使用行为及结果承担任何责任。 如使用者因违反本声明第 1、2 条规定,或因自身使用行为侵犯第三方合法权益、违反法律法规而产生任何纠纷、处罚、赔偿或法律责任,均由使用者自行承担全部责任,与开发者无关。 开发者保留在发现非法使用行为时,采取包括但不限于删除代码、终止开源服务、向有关部门举报等措施的权利。
-
风险提示 爬虫技术的使用存在法律及技术风险,使用者应自行评估使用场景的合法性及合规性,并承担因使用本框架可能产生的一切风险(包括但不限于法律风险、技术风险、数据安全风险等)。