【WebMagic】二、注解开发

注解开发简介

WebMagic支持使用独有的注解风格编写一个爬虫,引入webmagic-extension包即可使用此功能。

在注解模式下,使用一个简单对象加上注解,可以用极少的代码量就完成一个爬虫的编写。对于简单的爬虫,这样写既简单又容易理解,并且管理起来也很方便。

注解模式的开发方式是这样的:
1、首先定义你需要抽取的数据,并编写类。
2、在类上写明@TargetUrl注解,定义对哪些URL进行下载和抽取。
3、在类的字段上加上@ExtractBy注解,定义这个字段使用什么方式进行抽取。
4、定义结果的存储方式。


目标

爬取的网址为 http://blog.sina.com.cn/s/blog_58ae76e80100to5q.html 的内容

具体步骤

一、定义抽取的内容

编写Model类
一个github项目的名称、作者和简介三个信息

public class SinaBlogRepo {

    private String title;

    private String text;

    private String date;

}

二、定义如何发现URL

@TargetUrl 和 @HelpUrl
HelpUrl/TargetUrl是一个非常有效的爬虫开发模式,TargetUrl是我们最终要抓取的URL,最终想要的数据都来自这里;而HelpUrl则是为了发现这个最终URL,我们需要访问的页面。几乎所有垂直爬虫的需求,都可以归结为对这两类URL的处理:

  • TargetUrl是文章页,HelpUrl是列表页。

在这个例子中,TargetUrl是最终的项目内容页,HelpUrl则是项目列表页,它会展示所有项目的链接。

有了这些知识,我们就为这个例子定义URL格式:

@TargetUrl("http://blog.sina.com.cn/s/blog_\\w+.html")
public class SinaBlogRepo {
    ……
}
注意:TargetUrl中的自定义正则表达式
1、WebMagic自己定制的适合URL的正则表达式,主要由两点改动:
  • 将URL中常用的字符 " . " 默认做了转义【 不需要用 " \. ", 可以直接使用 “.”
  • 将URL中常用的字符 " * " 默认做了转义 【直接使用 " * " 可表示通配符,不需要 " .* "
    例如,https://github.com/*在这里是一个合法的表达式,它表示https://github.com/下的所有URL。

在WebMagic中,从TargetUrl页面得到的URL,只要符合TargetUrl的格式,也是会被下载的。
所以即使不指定HelpUrl也是可以的——例如某些博客页总会有“下一篇”链接,这种情况下无需指定HelpUrl。

2、sourceRegion

TargetUrl还支持定义sourceRegion,这个参数是一个XPath表达式,指定了这个URL从哪里得到——不在sourceRegion的URL不会被抽取。

三、定义如何抽取元素(单)

1、 @ExtractBy

一个用于抽取元素的注解,它描述了一种抽取规则。
主要作用于字段,它表示“使用这个抽取规则,将抽取到的结果保存到这个字段中”。例如:

  • 1、XPath
@ExtractBy(value = "//div[@class='articalTitle']/h2")
    private String title;

这里"//div[@id=‘readme’]/text()"是一个XPath表示的抽取规则,而抽取到的结果则会保存到readme字段中。

  • 2、其它

包括CSS选择器、正则表达式和JsonPath,在注解中指明type之后即可。

@ExtractBy(value = "div.BlogContent", type = ExtractBy.Type.Css)
private String content;
属性:notNull(默认为false)

@ExtractBy包含一个notNull属性,此字段不允许为空。如果为空,这条抽取到的结果会被丢弃。对于一些页面的关键性属性(例如文章的标题等),设置notnull为true,可以有效的过滤掉无用的页面。

2、 @ExtractByUrl

@ExtractByUrl是一个单独的注解,它的意思是“从URL中进行抽取”。

 @ExtractByUrl("https://github\\.com/(\\w+)/.*")
    private String author;

三*、定义如何在一个页面抽取多条结果

在类上使用@ExtractBy注解可以解决这个问题。
使用这个结果抽取一个区域,让这块区域对应一个结果。

@ExtractBy(value = "//ul[@id=\"promos_list2\"]/li")
public class QQMeishi {
    ……
}

四、结果的类型转换

Formatter机制

因为抽取到的内容总是String,而我们想要的内容则可能是其他类型。Formatter可以将抽取到的内容,自动转换成一些基本类型,而无需手动使用代码进行转换。
直接定义元素时候,定义成所需的元素,WebMagic可以完成自动转换。

@ExtractBy("//ul[@class='pagehead-actions']/li[1]//a[@class='social-count js-social-count']/text()")
private int star;
  • 自动转换支持的类型
    自动转换支持所有基本类型和装箱类型
    在这里插入图片描述
  • java.util.Date类型的转换。
    在转换时,需要指定Date的格式。格式按照JDK的标准来定义,具体规范可以看这里
@Formatter("yyyy-MM-dd HH:mm")
@ExtractBy("//div[@class='BlogStat']/regex('\\d+-\\d+-\\d+\\s+\\d+:\\d+')")
private Date date;
自定义Formatter(TODO)

实际上,除了自动类型转换之外,Formatter还可以做一些结果的后处理的事情。
要求:需要将抽取的结果作为结果的一部分,拼接上一部分字符串来使用
在这里,我们定义了一个StringTemplateFormatter。

public class StringTemplateFormatter implements ObjectFormatter<String> {

    private String template;

    @Override
    public String format(String raw) throws Exception {
        return String.format(template, raw);
    }

    @Override
    public Class<String> clazz() {
        return String.class;
    }

    @Override
    public void initParam(String[] extra) {
        template = extra[0];
    }
}
@Formatter(value = "author is %s",formatter = StringTemplateFormatter.class)
@ExtractByUrl("https://github\\.com/(\\w+)/.*")
private String author;

五、爬虫的创建和启动

1、OOSpider

注解模式的入口是OOSpider,它继承了Spider类,提供了特殊的创建方法,其他的方法是类似的。创建一个注解模式的爬虫需要一个或者多个Model类,以及一个或者多个PageModelPipeline——定义处理结果的方式。

public static OOSpider create(Site site, PageModelPipeline pageModelPipeline, Class... pageModels);
2、PageModelPipeline

注解模式下,处理结果的类叫做PageModelPipeline,通过实现它,你可以自定义自己的结果处理方式。

public interface PageModelPipeline<T> {
    public void process(T t, Task task);
}

PageModelPipeline与Model类是对应的,多个Model可以对应一个PageModelPipeline。可以通过addPageModel方法,在添加一个Model的同时,可以添加一个PageModelPipeline。

public OOSpider addPageModel(PageModelPipeline pageModelPipeline, Class... pageModels)

完整代码:

import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.model.ConsolePageModelPipeline;
import us.codecraft.webmagic.model.OOSpider;
import us.codecraft.webmagic.model.annotation.ExtractBy;
import us.codecraft.webmagic.model.annotation.ExtractByUrl;
import us.codecraft.webmagic.model.annotation.HelpUrl;
import us.codecraft.webmagic.model.annotation.TargetUrl;
import us.codecraft.webmagic.pipeline.FilePipeline;
import us.codecraft.webmagic.pipeline.JsonFilePageModelPipeline;

//在类上写明@TargetUrl注解,定义对哪些URL进行下载和抽取。
@TargetUrl("http://blog.sina.com.cn/s/blog_\\w+.html")
// @HelpUrl("http://blog\\.sina\\.com\\.cn/s/articlelist_1487828712_0_\\d+\\.html")
public class SinaBlogRepo {

    //在类的字段上加上@ExtractBy注解,定义这个字段使用什么方式进行抽取。
    @ExtractBy(value = "//div[@class='articalTitle']/h2")
    private String title;

    @ExtractBy("//div[@id='articlebody']//div[@class='articalContent']")
    private String text;

    @ExtractBy("//div[@class='articalTitle']/h2")
    private String date;

    public static void main(String[] args) {
        SinaBlogRepo ans = OOSpider.create(Site.me(), SinaBlogRepo.class).<SinaBlogRepo>get("http://blog.sina.com.cn/s/blog_58ae76e80100to5q.html");
        // OOSpider.create(Site.me().setSleepTime(1000), new ConsolePageModelPipeline(), SinaBlogRepo.class).addUrl("http://blog.sina.com.cn/s/blog_58ae76e80100to5q.html").thread(5).run();
        System.out.println(ans);
    }

    public String getTitle() {
        return title;
    }

    public String getText() {
        return text;
    }

    public String getDate() {
        return date;
    }

    @Override
    public String toString() {
        return "GithubRepo{" +
                "title='" + title + '\'' +
                ", text='" + text + '\'' +
                ", date='" + date + '\'' +
                '}';
    }
}

部分打印结果:
在这里插入图片描述

问题:WebMagic抓HTTPS时出现SSLExceptio

解决方法见:这里
修改源码中的类 buildSSLConnectionSocketFactory

SSLContext sc = SSLContext.getInstance("TLS");//将SSLv3改为TLS

参考文献

  • http://webmagic.io/docs/zh/posts/ch5-annotation/
  • https://blog.csdn.net/yan3013216087/article/details/84398608
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值