SpringBoot - 整合webmagic实现爬虫功能教程(附豆瓣数据抓取样例)
作者:hangge | 2024-08-26 09:41
1,基本介绍
(1)webmagic 是一个由国人开发的开源的 Java 垂直爬虫框架,目标是简化爬虫的开发流程,让开发者专注于逻辑功能的开发。webmagic 的核心非常简单,但是覆盖爬虫的整个流程,也是很好的学习爬虫开发的材料。
- 官网地址:https://webmagic.io/
- GitHub 主页:https://github.com/code4craft/webmagic
(2)webmagic 的主要特色:
- 完全模块化的设计,强大的可扩展性。
- 核心简单但是涵盖爬虫的全部流程,灵活而强大,也是学习爬虫入门的好材料。
- 提供丰富的抽取页面 API。
- 无配置,但是可通过“POJO + 注解”形式实现一个爬虫。
- 支持多线程。
- 支持分布式。
- 支持爬取 js 动态渲染的页面。
- 无框架依赖,可以灵活的嵌入到项目中去。
2,安装配置
在 Spring Boot 项目的 pom.xml 文件中添加 webmagic 的依赖即可:
(1)webmagic 主要包括两个包:
- webmagic-core:webmagic 核心部分,只包含爬虫基本模块和基本抽取器。webmagic-core 的目标是成为网页爬虫的一个教科书般的实现。
- webmagic-extension:webmagic 的扩展模块,提供一些更方便的编写爬虫的工具。包括注解格式定义爬虫、JSON、分布式等支持。
(2)webmagic 还包含两个可用的扩展包,因为这两个包都依赖了比较重量级的工具,所以从主要包中抽离出来,这些包需要下载源码后自己编译:
- webmagic-saxon:webmagic 与 Saxon 结合的模块。Saxon 是一个 XPath、XSLT 的解析工具,webmagic 依赖 Saxon 来进行 XPath2.0 语法解析支持。
- webmagic-selenium:webmagic 与 Selenium 结合的模块。Selenium 是一个模拟浏览器进行页面渲染的工具,webmagic 依赖 Selenium 进行动态页面的抓取。
<dependency> <groupId>us.codecraft</groupId> <artifactId>webmagic-core</artifactId> <version>0.10.0</version> </dependency> <dependency> <groupId>us.codecraft</groupId> <artifactId>webmagic-extension</artifactId> <version>0.10.0</version> </dependency>
3,使用样例
(1)我们要实现一个爬虫能够抓取豆瓣图书里面所有的小说信息,并且运行时能够自动翻页实现连续抓取:
(2)查看页面源码,可以看到相应元素信息如下:
注意:代码 30、31 行我每次只添加分页栏中的后页的链接,其实不必这么麻烦,可以将所有匹配到的分页链接集合都直接调用 page.addTargetRequests() 方法添加进来,即使跳转后的页面分页链接和之前的有重复,webmagic 也会自动剔除,确保不会重复抓取的,或者死循环的。
import us.codecraft.webmagic.Page; import us.codecraft.webmagic.Site; import us.codecraft.webmagic.Spider; import us.codecraft.webmagic.processor.PageProcessor; import java.util.Collections; import java.util.List; public class DoubanBookSpider implements PageProcessor { private Site site = Site.me().setRetryTimes(3).setSleepTime(1000); @Override public void process(Page page) { // 解析页面,提取数据 List<String> bookNames = page.getHtml().xpath("//*[@id='subject_list']//h2/a/text()").all(); List<String> bookInfos = page.getHtml() .xpath("//*[@id='subject_list']//div[@class='pub']/text()").all(); // 将数据打印到控制台 for (int i = 0; i < bookNames.size(); i++) { System.out.println("书名:" + bookNames.get(i) + " 信息:" + bookInfos.get(i)); } // 添加下一页的URL,继续爬取 List<String> links = page.getHtml().links() .regex("https://book.douban.com/tag/小说\\?start=\\d+&type=T").all(); if(links.size() > 0) { System.out.println("**************************************"); // 获取最后一个元素 String nextPageLink = links.get(links.size() - 1); page.addTargetRequests(Collections.singletonList(nextPageLink)); } } @Override public Site getSite() { return site; } public static void main(String[] args) { // 启动爬虫 Spider.create(new DoubanBookSpider()) .addUrl("https://book.douban.com/tag/小说") // 豆瓣图书小说标签页面 .run(); } }
(4)程序运行后爬虫便会自动访问豆瓣图书小说标签页面,并开始抓取数据。
附:使用注解编写爬虫
(1)webmagic-extension 包括了注解方式编写爬虫的方法,只需基于一个 POJO 增加注解即可完成一个爬虫。下面我们使用注解的方式定义一个爬虫:
注解说明:
- @TargetUrl 是我们最终要抓取的 URL,最终想要的数据都来自这里;
- @HelpUrl 则是为了发现这个最终 URL,我们需要访问的页面。
- @ExtractBy 注解主要作用于字段,它表示“使用这个抽取规则,将抽取到的结果保存到这个字段中”
import us.codecraft.webmagic.model.annotation.ExtractBy; import us.codecraft.webmagic.model.annotation.HelpUrl; import us.codecraft.webmagic.model.annotation.TargetUrl; import java.util.List; // 爬虫页面模型类,用于定义如何抽取目标网页中的数据。 @TargetUrl("https://book.douban.com/tag/小说*") @HelpUrl("https://book.douban.com/tag/小说\\?start=\\d+&type=T") public class DoubanBookPageModel { public List<String> getBookNames() { return bookNames; } public List<String> getBookInfos() { return bookInfos; } @ExtractBy("//*[@id='subject_list']//h2/a/text()") private List<String> bookNames; @ExtractBy("//*[@id='subject_list']//div[@class='pub']/text()") private List<String> bookInfos; }
(2)接着我们在程序中使用这个定义的爬虫,并将爬虫抓取的数据打印出来:
import us.codecraft.webmagic.Site; import us.codecraft.webmagic.Task; import us.codecraft.webmagic.model.ConsolePageModelPipeline; import us.codecraft.webmagic.model.OOSpider; public class DoubanBookSpider2 { public static void main(String[] args) { // 启动爬虫 OOSpider.create(Site.me(), new MyPageModelPipeline(), DoubanBookPageModel.class) .addUrl("https://book.douban.com/tag/小说").run(); } } // 自定义页面模型管道,继承自ConsolePageModelPipeline class MyPageModelPipeline extends ConsolePageModelPipeline { @Override public void process(Object o, Task task) { System.out.println("**************************************"); DoubanBookPageModel douban = (DoubanBookPageModel)o; // 将数据打印到控制台 for (int i = 0; i < douban.getBookNames().size(); i++) { System.out.println("书名:" + douban.getBookNames().get(i) + " 信息:" + douban.getBookInfos().get(i)); } } }
(3)程序运行的效果同前面的是一样的:
全部评论(0)