EasyCrawler-使用WebMagic注解爬取早呀日报

背景

WebMagic作为一个Java爬虫社区比较活跃的开源框架,肯定有不少东西可以学习的,而且最重要的是有使用手册(http://webmagic.io/docs/zh/)。这不,我温故而知新时(最近,项目比较闲,0 Bug,0 需求的我),发现了这家伙居然可以使用注解来进行爬虫。

WebMagic注解

看到使用手册的第5部分,我们可以看到WebMagic注解就那么一点东西,当然,这得是在你了解WebMagic和使用过WebMagic的基础下。
EasyCrawler-使用WebMagic注解爬取早呀日报_第1张图片
由图我们可以看到,其实注解的开发模式比较简单,就是用@TargetUrl注解来进行网站的下载和抽取,用@ExtractBy注解来进行信息的提取,最后通过实现不同的接口进行信息的处理(最后这句为剧透)。

爬取早呀日报

说多无味(谓),做多最实际,下面我们直接开始实战,在实战中去理解WebMagic注解的使用以及魅力所在。
这次要盘的目标是:早呀-2020-04-17【早报】
EasyCrawler-使用WebMagic注解爬取早呀日报_第2张图片
这种由微信公众号发的早报或文章。

今天要爬取的内容很简单,分别是:日报的时间,标题3个,各个标题对应的内容,效果图如下:
EasyCrawler-使用WebMagic注解爬取早呀日报_第3张图片
当然,这种东西直接用EasyCrawler是可以直接爬取到的,但是,别忘了我们今天的目标是:温故而知新。

首先

既然我们知道我们今天要爬取的内容,那么我们肯定要先把基本的东西给搭建好了,从调用到写入数据库,这过程一步都不可以少哦!
EasyCrawler-使用WebMagic注解爬取早呀日报_第4张图片

第二步

按照WebMagic的说法,我们得先定义一个我们爬取的内容

@Data
//匹配https://blog.love2love.top/archives为前缀的所有网址
@TargetUrl("https://blog.love2love.top/archives/*.html")
public class ZaoYaDTO {

    //用ExtractBy注解的字段会被自动抽取并填充
    //默认是xpath语法
    @ExtractBy(value = "#main > div.layout > div.article > article > div.article-meta > span:nth-child(4)",type = ExtractBy.Type.Css)
    private String date;
    @ExtractBy(value = "//*[@id=\"main\"]/div[2]/div[1]/article/div[4]/ul[1]/li/h3/strong/text()")
    private String title1;
    @ExtractBy(value = "//*[@id=\"main\"]/div[2]/div[1]/article/div[4]/p[1]/text()")
    private List<String> content11;
    @ExtractBy(value = "//*[@id=\"main\"]/div[2]/div[1]/article/div[4]/p[2]/text()")
    private List<String> content12;
    @ExtractBy(value = "//*[@id=\"main\"]/div[2]/div[1]/article/div[4]/p[3]/text()")
    private List<String> content13;
    @ExtractBy(value = "//*[@id=\"main\"]/div[2]/div[1]/article/div[4]/p[4]/text()")
    private List<String> content14;
    @ExtractBy(value = "//*[@id=\"main\"]/div[2]/div[1]/article/div[4]/p[5]/text()")
    private List<String> content15;
    @ExtractBy("//*[@id=\"main\"]/div[2]/div[1]/article/div[4]/ul[2]/li/h3/strong/text()")
    private String title2;
    @ExtractBy("//*[@id=\"main\"]/div[2]/div[1]/article/div[4]/p[6]/text()")
    private List<String> content2;
    @ExtractBy("//*[@id=\"main\"]/div[2]/div[1]/article/div[4]/ul[3]/li/h3/strong/text()")
    private String title3;
    @ExtractBy("//*[@id=\"main\"]/div[2]/div[1]/article/div[4]/p[7]/text()")
    private List<String> content3;
    @ExtractBy("//*[@id=\"main\"]/div[2]/div[1]/article/div[4]/ul[4]/li/h3/strong/text()")
    private String title4;
    @ExtractBy("//*[@id=\"main\"]/div[2]/div[1]/article/div[4]/p[8]/text()")
    private List<String> content4;
}

这里我们可以看到@ExtractBy是支持多种不同的选择器去提取信息,这里主要用的是XPath和CSS选择器,默认是XPath,使用CSS时,加个type = ExtractBy.Type.Css即可。
另外,这里可能会有秀儿问:“content11,content12是啥啊?头条新闻不就一个框框吗?你还一段段爬啊?” 秀儿,你坐下!这里为什么这么定义了?一方面是因为,我爬取时发现“头条新闻”这里的每一段是一个p标签来的,既没有id也没有div去包着,估计做这个网站的人前端知识不太好(或者有可能是为了防爬虫[奸笑]),另一方面,因为是用XPath选择器的,而XPath选择器中是可以使用谓语来指定第几个或者某几个的,但是我发现。。。。。WebMagic不支持!! [哭笑不得]
参考如下:
[转]webmagic的xpath中last()函数无法使用?

XPath选择器谓语:EasyCrawler-使用WebMagic注解爬取早呀日报_第5张图片

第三步

有了指定的抽取地址(补:@TargetUrl支持正则表达式,具体看使用手册)和抽取的信息后,我们只需要将程序跑起来,再做数据处理即可。

@Slf4j
@Service
public class ZaoYaService implements PageModelPipeline<ZaoYaDTO> {

    private Site site = Site.me().setRetryTimes(3).setSleepTime(100);

    @Autowired
    private ZaoYaMapper zaoYaMapper;


    public void getZaoYa() {
        //启动webmagic
        OOSpider.create(site,this,ZaoYaDTO.class)
                .addUrl("https://blog.love2love.top/archives/352.html?from=timeline")
                .thread(5)
                .run();
    }

    @Override
    public void process(ZaoYaDTO zaoYaDTO, Task task) {
        List<String> content1 = new ArrayList<>();
        content1.addAll(zaoYaDTO.getContent11());
        content1.addAll(zaoYaDTO.getContent12());
        content1.addAll(zaoYaDTO.getContent13());
        content1.addAll(zaoYaDTO.getContent14());
        content1.addAll(zaoYaDTO.getContent15());
        ZaoYa zaoYa = ZaoYa.builder()
                .id(IdUtils.getRandomIdByUUID())
                .newsDate(zaoYaDTO.getDate())
                .title1(zaoYaDTO.getTitle1())
                .title2(zaoYaDTO.getTitle2())
                .title3(zaoYaDTO.getTitle3())
                .title4(zaoYaDTO.getTitle4())
                .content1(JSONArray.fromObject(content1).toString())
                .content2(JSONArray.fromObject(zaoYaDTO.getContent2()).toString())
                .content3(JSONArray.fromObject(zaoYaDTO.getContent3()).toString())
                .content4(JSONArray.fromObject(zaoYaDTO.getContent4()).toString())
                .createTime(new Date())
                .build();
        zaoYaMapper.insert(zaoYa);
    }
}

这里我使用的是PageModelPipeline这个接口,一开始是使用AfterExtractor的
区别如下:
EasyCrawler-使用WebMagic注解爬取早呀日报_第6张图片
EasyCrawler-使用WebMagic注解爬取早呀日报_第7张图片
所以,如果你这里使用了AfterExtractor的话,Mapper就会报空指针,但是对应字段的数据抽取是没有问题,会保留着以供使用。

最后,Git传送门:https://github.com/a81579261/EasyCrawler

PS:程序并不完美,数据是爬取到了,但是由于多个页面定位不正确,导致数据放的位置不对。由于,本Demo仅用于学习WebMagic的注解,就没有多加处理了。如有人处理了,可以无私贡献下代码,我会进行更新合并的,谢谢。

你可能感兴趣的:(Java,爬虫,WebMagic)