java爬虫抓取动态网页(Java垂直爬虫框架(一)——webmagic)
优采云 发布时间: 2022-03-11 17:14java爬虫抓取动态网页(Java垂直爬虫框架(一)——webmagic)
webmagic 是一个开源的 Java 垂直爬虫框架。其目标是简化爬虫的开发过程,让开发者专注于逻辑功能的开发。webmagic的核心很简单,但是涵盖了爬虫的全过程,也是学习爬虫开发的好资料。
网络爬虫是一种技术,webmagic致力于降低这项技术的实现成本,但出于对资源提供者的尊重,webmagic不会做防阻塞的事情,包括:验证码破解、代理切换、自动登录等...
作者黄宜华()曾在原公司从事垂直履带开发工作一年。Webmagic 是为解决爬虫开发的一些重复性工作而生成的框架。
webmagic的架构和设计参考了以下两个项目,感谢以下两个项目的作者:
python爬虫scrapy
Java爬虫蜘蛛侠
webmagic 遵循 Apache 2.0 协议,您可以自由使用和修改它。如果您有任何不便或问题,欢迎您在 github 上提交问题,或在 oschina 讨论模块中提问。
使用maven下载安装
webmagic 使用 maven 来管理依赖,你可以通过在项目中添加相应的依赖来使用 webmagic:
us.codecraft
webmagic-core
0.4.2
us.codecraft
webmagic-extension
0.4.2
项目结构
webmagic主要包括两个包:
webmagic 还包括两个可用的扩展包。因为这两个包依赖于比较重量级的工具,所以是从主包中提取出来的。这些包需要在源码之后自行下载编译:
在您的项目中,您可以根据需要依赖不同的包。
不使用maven
不使用maven的用户可以下载带有二进制jar包的版本(感谢oschina):
git clone http://git.oschina.net/flashsword20/webmagic.git
在 bin/lib 目录下,可以在 IDE 中直接导入项目所依赖的所有 jar 包。
第一个爬虫自定义PageProcessor
PageProcessor 是 webmagic-core 的一部分,您可以通过自定义 PageProcessor 来实现自己的爬虫逻辑。下面是一段爬取 osc 博客的代码:
public class OschinaBlogPageProcesser implements PageProcessor {
private Site site = Site.me().setDomain("my.oschina.net")
.addStartUrl("http://my.oschina.net/flashsword/blog");
@Override
public void process(Page page) {
List links = page.getHtml().links().regex("http://my\\.oschina\\.net/flashsword/blog/\\d+").all();
page.addTargetRequests(links);
page.putField("title", page.getHtml().xpath("//div[@class='BlogEntity']/div[@class='BlogTitle']/h1").toString());
page.putField("content", page.getHtml().$("div.content").toString());
page.putField("tags",page.getHtml().xpath("//div[@class='BlogTags']/a/text()").all());
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) {
Spider.create(new OschinaBlogPageProcesser())
.pipeline(new ConsolePipeline()).run();
}
}
这里要爬取的URL是通过page.addTargetRequests()方法添加的,提取结果通过page.putField()保存。page.getHtml().xpath() 按照一定的规则提取结果,提取支持链式调用。调用后,toString() 表示转换为单个 String,all() 表示将其转换为 String 列表。
Spider 是爬虫的入口类。Pipeline 是结果输出和持久化的接口,其中 ConsolePipeline 表示将结果输出到控制台。
执行这个main方法,可以在控制台看到抓取结果。默认情况下,webmagic 的抓取间隔为 3 秒,请耐心等待。您可以使用 site.setSleepTime(int) 修改此值。该站点还具有一些用于修改爬网属性的方法。
使用注释
webmagic-extension 包括通过注解编写爬虫的方法。只需要基于POJO添加注解即可完成爬虫。下面依然是一段抓取oschina博客的代码,功能和OschinaBlogPageProcesser完全一样:
@TargetUrl("http://my.oschina.net/flashsword/blog/\\d+")
public class OschinaBlog {
@ExtractBy("//title")
private String title;
@ExtractBy(value = "div.BlogContent",type = ExtractBy.Type.Css)
private String content;
@ExtractBy(value = "//div[@class='BlogTags']/a/text()", multi = true)
private List tags;
@Formatter("yyyy-MM-dd HH:mm")
@ExtractBy("//div[@class='BlogStat']/regex('\\d+-\\d+-\\d+\\s+\\d+:\\d+')")
private Date date;
public static void main(String[] args) {
OOSpider.create(
Site.me().addStartUrl("http://my.oschina.net/flashsword/blog"),
new ConsolePageModelPipeline(), OschinaBlog.class).run();
}
}
本例定义了一个Model类,Model类的“title”、“content”、“tags”字段都是要提取的属性。这个类在 Pipeline 中是可重用的。
有关如何使用注释的详细信息,请参阅下面的 webmagic-extension 注释模块。
模块详情 webmagic-core
webmagic-core是爬虫的核心框架,只收录了爬虫各个功能模块的核心功能。webmagic-core 的目标是成为网络爬虫的教科书实现。
本节部分内容摘自作者的博文 Webmagic Design Mechanism and Principle - How to Develop a Java Crawler。
webmagic-core的模块划分
webmagic-core指scrapy的模块划分,分为Spider(整个爬虫的调度框架)、Downloader(页面下载)、PageProcessor(链接提取和页面分析)、Scheduler(URL管理)、Pipeline(离线分析和持久化) ) 几个部分。只是scrapy是通过中间件扩展的,而webmagic是通过定义这些接口,将它们不同的实现注入到主框架类Spider中来扩展的。
蜘蛛类(核心调度)
Spider是爬虫的入口类。爬虫的接口调用采用链式API设计,其他所有功能都通过接口注入到爬虫中。以下是启动更复杂爬虫的示例。
Spider.create(sinaBlogProcessor)
.scheduler(new FileCacheQueueScheduler("/data/temp/webmagic/cache/"))
.pipeline(new FilePipeline())
.thread(10).run();
Spider的核心处理流程非常简单,代码如下:
private void processRequest(Request request) {
Page page = downloader.download(request, this);
if (page == null) {
sleep(site.getSleepTime());
return;
}
pageProcessor.process(page);
addRequest(page);
for (Pipeline pipeline : pipelines) {
pipeline.process(page, this);
}
sleep(site.getSleepTime());
}
Spider还包括一个方法test(String url),只爬取单个页面,用于测试提取效果。
PageProcessor(页面分析和链接提取)
页面分析是垂直爬虫中需要定制的部分。在 webmagic-core 中,通过实现 PageProcessor 接口来实现自定义爬虫。PageProcessor 有两个核心方法:public void process(Page page) 和 public Site getSite()。
Selector 是 webmagic 为简化页面提取和开发而开发的一个独立模块,是 webmagic-core 的主要关注点。它集成了 CSS Selector、XPath 和正则表达式,并且可以进行链式提取。
//content是用别的爬虫工具抽取到的正文
List links = page.getHtml()
.$("div.title") //css 选择,Java里虽然很少有$符号出现,不过貌似$作为方法名是合法的
.xpath("//@href") //提取链接
.regex(".*blog.*") //正则匹配过滤
.all(); //转换为string列表
webmagic 收录一个 SmartContentSelector 类,它会自动提取页面的正文。相信 Evernote Clearly 会对它的自动文本提取技术印象深刻。这项技术也称为可读性。当然,webmagic 对 Readability 的实现还是比较粗糙的,但是还是有一些学习价值的。
webmagic的XPath解析使用了作者的另一个开源项目:Xsoup,一个基于Jsoup的XPath解析器。Xsoup 扩展了 XPath 的语法并支持一些自定义函数。这些函数通过在 XPath 末尾添加 /name-of-function() 来使用,例如:"//div[@class='BlogStat']/regex('\\d+-\\d+-\\ d+ \\s+\\d+:\\d+')"。
功能
阐明
文本(n)
第 n 个文本节点(0 表示全取)
全部文本()
所有文本,包括子节点
整洁的文本()
使用智能换行收录子节点的所有文本
html()
内部 html(不包括当前标签本身)
外部HTML()
外部 html(包括当前标签本身)
正则表达式(@attr,expr,组)
正则表达式,@attr为提取属性(可省略),expr为表达式内容,group为捕获组(可省略,默认为0)
基于 Saxon,webmagic 提供对 XPath2.0 语法的支持。XPath2.0 语法支持内部函数、逻辑控制等,是一门完整的语言。如果你熟悉 XPath2.0 语法,不妨一试(需要引入 webmagic-saxon 包)。
webmagic-samples 包有一些为站点定制的 PageProcessor 用于学习目的。
下载器(页面下载)
Downloader 是 webmagic 中下载页面的接口。主要方法有:
Downloader 目前有几种实现方式:
调度程序(URL 管理)
调度器是webmagic的管理模块。您可以通过实施调度程序自定义您自己的 URL 管理器。调度器主要包括两个方法:
webmagic 目前有调度器的三种实现:
管道(后续处理和持久化)
Pipeline 是输出和持久化最终提取结果的接口。它只包括一种方法:
webmagic 收录以下 Pipeline 的实现:
webmagic 目前不支持持久化到数据库,但是结合其他工具,持久化到数据库很容易。这里,我们来看一段webmagic结合JFinal持久化到数据库的代码。因为 JFinal 目前不支持 maven,所以这段代码没有放在 webmagic-samples 中。
webmagic 扩展
webmagic-extension是为了方便开发爬虫而实现的一些功能模块。这些功能完全基于webmagic-core框架,包括编写爬虫、分页、以注解形式分发等功能。
注释模块
webmagic-extension 收录注释模块。为什么会有注释?
因为 PageProcessor 的方式灵活而强大,它并没有解决两个问题:
注解的核心是Model类,它本身就是一个POJO。这个 Model 类用于传递和保存页面,最后获取结果数据。注解方式直接将提取和数据绑定,方便编写和维护。
注解方法其实是通过一个PageProcessor--ModelPageProcessor的实现来完成的,所以对webmagic-core代码没有影响。还是以抓取OschinaBlog的程序为例:
@TargetUrl("http://my.oschina.net/flashsword/blog/\\d+")
public class OschinaBlog {
@ExtractBy("//title")
private String title;
@ExtractBy(value = "div.BlogContent",type = ExtractBy.Type.Css)
private String content;
@ExtractBy(value = "//div[@class='BlogTags']/a/text()", multi = true)
private List tags;
@Formatter("yyyy-MM-dd HH:mm")
@ExtractBy("//div[@class='BlogStat']/regex('\\d+-\\d+-\\d+\\s+\\d+:\\d+')")
private Date date;
public static void main(String[] args) {
OOSpider.create(
Site.me().addStartUrl("http://my.oschina.net/flashsword/blog"),
new ConsolePageModelPipeline(), OschinaBlog.class).run();
}
}
注释部分包括以下内容:
类型转换
webmagic的注解方式支持提取结果的类型转换,使得提取结果不需要是String类型,可以是任意类型。webmagic 内置了对基本类型的支持(需要保证提取结果可以转换为对应的类型)。
@ExtractBy("//ul[@class='pagehead-actions']/li[1]//a[@class='social-count js-social-count']/text()")
private int star;
提取结果也可以是 java.util.Date 类型,但您需要指定日期的格式:
@Formatter("yyyy-MM-dd HH:mm")
@ExtractBy("//div[@class='BlogStat']/regex('\\d+-\\d+-\\d+\\s+\\d+:\\d+')")
private Date date;
您还可以编写一个实现 ObjectFormatter 接口的类来执行您自己的类型解析。要使用您自己的类,您需要调用 ObjectFormatters.put() 来注册该类。
OOSpider.create(
Site.me().addStartUrl("http://www.oschina.net"),
new ConsolePageModelPipeline(),
OschinaBlog.clas,OschinaAnswer.class).run();
OOSpider会根据TargetUrl调用不同的Model进行解析。
分散式
在 webmagic-extension 中,通过 redis 管理 URL 以达到分布式的效果。但是对于分布式爬虫来说,只有程序可以分布式运行,不能满足*敏*感*词*爬取的需要。Webmagic 以后可能会添加一些任务管理和监控功能。也欢迎用户提交代码并为 webmagic 做出贡献。