Home> Java> javaTutorial> body text

Learning summary of Java crawler framework WebMagic

WBOY
Release: 2022-10-11 15:31:15
forward
2115 people have browsed it

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于WebMagic的相关内容,WebMagic是一个简单灵活的Java爬虫框架,分为核心和扩展两部分,下面一起来看一下,希望对大家有帮助。

Learning summary of Java crawler framework WebMagic

推荐学习:《java视频教程

概述

WebMagic是一个简单灵活的Java爬虫框架。基于WebMagic,可以快速开发出一个高效、易维护的爬虫。

WebMagic分为核心和扩展两部分。核心部分(webmagic-core)是一个精简的、模块化的爬虫实现,而扩展部分则包括一些便利的、实用性的功能。

特性

简单的API,可快速上手

模块化的结构,可轻松扩展

提供多线程和分布式支持

架构

WebMagic的结构分为Downloader、PageProcessor、Scheduler、Pipeline四大组件,并由Spider将它们彼此组织起来。

四大组件对应爬虫生命周期中的下载、处理、管理和持久化等功能。WebMagic的设计参考了Scapy,实现方式更加Java化一些。

Spider则将这几个组件组织起来,让它们可以互相交互,流程化的执行,可以认为Spider是一个大的容器,它也是WebMagic逻辑的核心。

Learning summary of Java crawler framework WebMagic

四大组件

Downloader

Downloader负责从互联网上下载页面,以便后续处理。WebMagic默认使用了Apache HttpClient作为下载工具。

PageProcessor

PageProcessor负责解析页面,抽取有用信息,以及发现新的链接。WebMagic使用Jsoup作为HTML解析工具,并基于其开发了解析XPath的工具Xsoup。

在这四个组件中,PageProcessor对于每个站点每个页面都不一样,是需要使用者定制的部分。

Scheduler

Scheduler负责管理待抓取的URL,以及一些去重的工作。WebMagic默认提供了JDK的内存队列来管理URL,并用集合来进行去重。也支持使用Redis进行分布式管理。

Pipeline

Pipeline负责抽取结果的处理,包括计算、持久化到文件、数据库等。WebMagic默认提供了“输出到控制台”和“保存到文件”两种结果处理方案。

Pipeline定义了结果保存的方式,如果你要保存到指定数据库,则需要编写对应的Pipeline。对于一类需求一般只需编写一个Pipeline。

数据流转对象

Request

Request是对URL地址的一层封装,一个Request对应一个URL地址。它是PageProcessor与Downloader交互的载体,也是PageProcessor控制Downloader唯一方式。

除了URL本身外,它还包含一个Key-Value结构的字段extra。你可以在extra中保存一些特殊的属性,然后在其他地方读取,以完成不同的功能。例如附加上一个页面的一些信息等。

Page

Page代表了从Downloader下载到的一个页面——可能是HTML,也可能是JSON或者其他文本格式的内容。

Page是WebMagic抽取过程的核心对象,它提供一些方法可供抽取、结果保存等。

ResultItems

ResultItems相当于一个Map,它保存PageProcessor处理的结果,供Pipeline使用。它的API与Map很类似,值得注意的是它有一个字段skip,若设置为true,则不应被Pipeline处理。

控制爬虫运转的引擎Spider

Spider是WebMagic内部流程的核心。Downloader、PageProcessor、Scheduler、Pipeline都是Spider的一个属性,这些属性是可以自由设置的,通过设置这个属性可以实现不同的功能。Spider也是WebMagic操作的入口,它封装了爬虫的创建、启动、停止、多线程等功能。

以下是一个设置各个组件,并且设置多线程和启动的例子。

public static void main(String[] args) { Spider.create(new GithubRepoPageProcessor()) //从https://github.com/code4craft开始抓 .addUrl("https://github.com/code4craft") //设置Scheduler,使用Redis来管理URL队列 .setScheduler(new RedisScheduler("localhost")) //设置Pipeline,将结果以json方式保存到文件 .addPipeline(new JsonFilePipeline("D:\\data\\webmagic")) //开启5个线程同时执行 .thread(5) //启动爬虫 .run(); }
Copy after login

WebMagic的基本使用

添加WebMagic的核心与扩展依赖

 us.codecraft webmagic-core 0.7.5   us.codecraft webmagic-extension 0.7.5 
Copy after login

爬虫实现

public class MyJobProcessor implements PageProcessor { public void process(Page page) { List all = page.getHtml().css("span.s_btn_wr").css("input").all(); page.putField("title", all.get(0)); } private Site site = Site.me() //设置编码 .setCharset("utf8") //设置超时时间,单位是ms毫秒 .setTimeOut(10000) //设置重试的间隔时间 .setRetrySleepTime(3000) //设置重试次数 .setSleepTime(3); public Site getSite() { return site; } public static void main(String[] args) { Spider.create(new MyJobProcessor()) //初始访问url地址 .addUrl("http://www.baidu.com") .run(); } }
Copy after login
get page: http://www.baidu.com title:
Copy after login

爬虫的编写过程

实现PageProcessor

PageProcessor的定制分为三个部分,分别是爬虫的配置、页面元素的抽取和链接的发现

爬虫配置

爬虫的配置,包括编码、抓取间隔、超时时间、重试次数等,也包括一些模拟的参数,例如User Agent、cookie,以及代理的设置。

private Site site = Site.me() //设置编码 .setCharset("utf8") //设置超时时间,单位是ms毫秒 .setTimeOut(10000) //设置重试的间隔时间 .setRetrySleepTime(3000) //设置重试次数 .setSleepTime(3);
Copy after login

抽取页面元素

页面元素的抽取是爬虫的核心部分:对于下载到的Html页面,如何从中抽取到想要的信息?

WebMagic主要使用三种抽取技术:XPath、正则表达式和CSS选择器。对于JSON格式的内容,可使用JsonPath进行解析

XPath

获取属性class=myClass的div标签,里面的h1标签的内容

page.getHtml().xpath("//div[@class=myClass]/h1/text()")
Copy after login

CSS选择器

CSS选择器是与XPath类似的语言。Jsoup的选择器比XPath写起来要简单一些,但是如果写复杂一点的抽取规则,就相对要麻烦一点。

获取属性class为myClass的div标签下的直接子元素h1标签

page.getHtml().css("div.mt>h1").toString()
Copy after login

可使用:nth-child(n)选择第几个元素,但是注意:需要使用直接子元素才可以选择第几个元素

如: 选择第一个元素

page.getHtml().css("div#myId > ul > li:nth-child(1) a").toString()
Copy after login

正则表达式

正则表达式则是一种通用的文本抽取语言。在这里一般用于获取url地址。

匹配所有https://github.com/code4craft/webmagic这样的链接。

page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/\\w+/\\w+)").all());
Copy after login
Copy after login

JsonPath

JsonPath是于XPath很类似的一个语言,它用于从Json中快速定位一条内容。

链接的发现

一个站点的页面是很多的,一开始不可能全部列举出来,于是如何发现后续的链接,是一个爬虫不可缺少的一部分。

page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/\\w+/\\w+)").all());
Copy after login
Copy after login

page.getHtml().links().regex("(https://github\\.com/\\w+/\\w+)").all()用于获取所有满足https:/ /github\.com/\w+/\w+这个正则表达式的链接

page.addTargetRequests()则将这些链接加入到待抓取的队列中去。

Selectable抽取元素

Selectable相关的抽取元素链式API是WebMagic的一个核心功能。使用Selectable接口,就可以直接完成页面元素的链式抽取,也无需去关心抽取的细节。

上述page.getHtml()返回的是一个Html对象,它实现了Selectable接口。这个接口包含一些重要的方法,将它分为两类:抽取部分和获取结果部分。

抽取部分API

抽取部分API返回的都是一个Selectable接口,是支持链式调用的。

Learning summary of Java crawler framework WebMagic

获取结果的API

当链式调用结束时,一般都想要拿到一个字符串类型的结果。这时候就需要用到获取结果的API了。

一条抽取规则,无论是XPath、CSS选择器或者正则表达式,总有可能抽取到多条元素。WebMagic对这些进行了统一,可以通过不同的API获取到一个或者多个元素。

Learning summary of Java crawler framework WebMagic

注意:当有多条数据的时候,使用get()和toString()都是获取第一个url地址。

使用Pipeline保存结果

如何将抓取的结果保存下来?WebMagic用于保存结果的组件叫做Pipeline。

例如通过“控制台输出结果”这件事也是通过一个内置的Pipeline完成的,它叫做ConsolePipeline。

想要把结果用Json的格式保存下来,只需要将Pipeline的实现换成"JsonFilePipeline"就可以了。

想要把结果用保存到文件中,只将Pipeline的实现换成"FilePipeline"就可以了。

public static void main(String[] args) { Spider.create(new GithubRepoPageProcessor()) // 初始访问url地址 .addUrl("https://github.com/code4craft") .addPipeline(new JsonFilePipeline("D:\\webmagic\\")) //.addPipeline(new FilePipeline("D:\\webmagic\\")) //开启5个线程抓取 .thread(5) //启动爬虫 .run(); }
Copy after login

爬虫的配置、启动和终止

Spider启动入口

Spider是爬虫启动的入口。在启动爬虫之前,需要使用一个PageProcessor创建一个Spider对象,然后使用run()进行启动。同时Spider的其他组件(Downloader、Scheduler、Pipeline)都可以通过set方法来进行设置。

Learning summary of Java crawler framework WebMagic

Site爬虫配置

对站点本身的一些配置信息,例如编码、HTTP头、超时时间、重试策略等、代理等,都可以通过设置Site对象来进行配置。

Learning summary of Java crawler framework WebMagic

rivate Site site = Site.me() .setCharset("UTF-8")//编码 .setSleepTime(1)//抓取间隔时间 .setTimeOut(1000*10)//超时时间 .setRetrySleepTime(3000)//重试时间 .setRetryTimes(3);//重试次数
Copy after login

配置代理

代理服务器

有些网站不允许爬虫进行数据爬取,因为会加大服务器的压力。其中一种最有效的方式是通过ip+时间进行鉴别,因为正常人不可能短时间开启太多的页面,发起太多的请求。

使用WebMagic可以设置爬取数据的时间,但是会大大降低爬取数据的效率。如果ip被禁了,就有必要使用代理服务器来爬取数据。

代理(Proxy),也称网络代理,是一种特殊的网络服务,允许一个网络终端(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。

提供代理服务的电脑系统或其它类型的网络终端称为代理服务器(Proxy Server)。一个完整的代理请求过程为:客户端首先与代理服务器创建连接,接着根据代理服务器所使用的代理协议,请求对目标服务器创建连接、或者获得目标服务器的指定资源。

使用代理服务器

WebMagic使用的代理对象是APIProxyProvider。代理由HttpClientDownloader设置。

Learning summary of Java crawler framework WebMagic

ProxyProvider有一个默认实现:SimpleProxyProvider。它是一个基于简单Round-Robin的、没有失败检查的ProxyProvider。可以配置任意个候选代理,每次会按顺序挑选一个代理使用。它适合用在自己搭建的比较稳定的代理的场景。

如果需要根据实际使用情况对代理服务器进行管理(例如校验是否可用,定期清理、添加代理服务器等),只需要自己实现APIProxyProvider

在Spider启动入口处配置代理

public void Process() { // 创建下载器Downloader HttpClientDownloader httpClientDownloader = new HttpClientDownloader(); // 给下载器设置代理服务器信息 Proxy proxy = new Proxy("183.166.148.28", 64305); httpClientDownloader.setProxyProvider(SimpleProxyProvider.from(proxy)); Spider.create(new ProxyTest()) // 淘宝获取本机IP地址 .addUrl("https://www.taobao.com/help/getip.php") .setDownloader(httpClientDownloader) .run(); }
Copy after login

Scheduler组件

概述

Scheduler是WebMagic中进行URL管理的组件。

Scheduler包括两个作用:

对待抓取的URL队列进行管理。

对已抓取的URL进行去重。

WebMagic内置了几个常用的Scheduler。如果只是在本地执行规模比较小的爬虫,那么基本无需定制Scheduler

Learning summary of Java crawler framework WebMagic

对Scheduler的内部实现进行了重构,去重部分被单独抽象成了一个接口:DuplicateRemover,从而可以为同一个Scheduler选择不同的去重方式,以适应不同的需要,目前提供了两种去重方式。

Learning summary of Java crawler framework WebMagic

所有默认的Scheduler都使用HashSetDuplicateRemover来进行去重,除了RedisScheduler。

RedisScheduler是使用Redis的set进行去重,其他的Scheduler默认都使用HashSetDuplicateRemover来进行去重。

如果URL较多,使用HashSetDuplicateRemover会比较占用内存,可尝试BloomFilterDuplicateRemover

使用布隆过滤器

布隆过滤器 (Bloom Filter)是一种space efficient的概率型数据结构,用于判断一个元素是否在集合中。在垃圾邮件过滤的黑白名单方法、爬虫(Crawler)的网址判重模块中等等经常被用到。

哈希表也能用于判断元素是否在集合中,但是布隆过滤器只需要哈希表的1/8或1/4的空间复杂度就能完成同样的问题。

布隆过滤器可以插入元素,但不可以删除已有元素。其中的元素越多,误报率越大,但是漏报是不可能的。

原理:

布隆过滤器需要的是一个位数组(和位图类似)和K个映射函数(和Hash表类似),在初始状态时,对于长度为m的位数组array,它的所有位被置0。

如果要使用BloomFilter,必须要加入以下依赖:

  com.google.guava guava 31.1-jre 
Copy after login

添加布隆过滤器

public static void main(String[] args) { Spider.create(new JobProcessor()) //初始访问url地址 .addUrl("https://github.com/code4craft") .addPipeline(new FilePipeline("D:/webmagic/")) .setScheduler(new QueueScheduler() .setDuplicateRemover(new BloomFilterDuplicateRemover(10000000))) //参数设置需要对多少条数据去重 .thread(1)//设置线程数 .run(); }
Copy after login
public boolean isDuplicate(Request request, Task task) { boolean isDuplicate = this.bloomFilter.mightContain(this.getUrl(request)); if (!isDuplicate) { this.bloomFilter.put(this.getUrl(request)); this.counter.incrementAndGet(); } return isDuplicate; }
Copy after login

打开布隆过滤器BloomFilterDuplicateRemover,在isDuplicate方法处可断点验证

Learning summary of Java crawler framework WebMagic

对比

HashSet

使用java中的HashSet不能重复的特点去重。优点是容易理解。使用方便。缺点:占用内存大,性能较低。

Redis去重

使用Redis的set进行去重。优点是速度快(Redis本身速度就很快),而且去重不会占用爬虫服务器的资源,可以处理更大数据量的数据爬取。缺点:需要准备Redis服务器,增加开发和使用成本。

布隆过滤器(BloomFilter)

使用布隆过滤器也可以实现去重。优点是占用的内存要比使用HashSet要小的多,也适合大量数据的去重操作。缺点:有误判的可能。没有重复可能会判定重复,但是重复数据一定会判定重复。

布隆过滤器的实现

public class BloomFilter { /** * BitSet初始分配2^24个bit */ private static final int DEFAULT_SIZE = 1 << 24; /** * 不同哈希函数的种子,一般应取质数 */ private static final int[] seeds = new int[]{5, 7, 11, 13, 31, 37}; private BitSet bits = new BitSet(DEFAULT_SIZE); /** * 哈希函数对象 */ private SimpleHash[] func = new SimpleHash[seeds.length]; public BloomFilter() { for (int i = 0; i < seeds.length; i++) { func[i] = new SimpleHash(DEFAULT_SIZE, seeds[i]); } } /** * 将url标记到bits中 * * @param str */ public void add(String str) { for (SimpleHash f : func) { bits.set(f.hash(str), true); } } /** * 判断是否已经被bits标记 * * @param str * @return */ public boolean contains(String str) { if (StringUtils.isBlank(str)) { return false; } boolean ret = true; for (SimpleHash f : func) { ret = ret && bits.get(f.hash(str)); } return ret; } /** * 哈希函数类 */ public static class SimpleHash { private int cap; private int seed; public SimpleHash(int cap, int seed) { this.cap = cap; this.seed = seed; } /** * hash函数,采用简单的加权和hash * * @param value * @return */ public int hash(String value) { int result = 0; int len = value.length(); for (int i = 0; i < len; i++) { result = seed * result + value.charAt(i); } return (cap - 1) & result; } } }
Copy after login

Pipeline组件

概述

Pileline是抽取结束后,进行处理的部分,它主要用于抽取结果的保存,也可以定制Pileline可以实现一些通用的功能。

Pipeline是将PageProcessor抽取的结果,继续进行处理,在Pipeline中完成的功能,基本上也可以直接在PageProcessor实现。

Pipeline的接口定义

public interface Pipeline { // ResultItems保存了抽取结果,它是一个Map结构 // 在page.putField(key,value)中保存的数据,可以通过ResultItems.get(key)获取 public void process(ResultItems resultItems, Task task); }
Copy after login

Pipeline存在原因

为了模块分离。“页面抽取”和“后处理、持久化”是爬虫的两个阶段,将其分离开来,一个是代码结构比较清晰,另一个是以后也可能将其处理过程分开,分开在独立的线程以至于不同的机器执行。

Pipeline的功能比较固定,更容易做成通用组件。每个页面的抽取方式千变万化,但是后续处理方式则比较固定,例如保存到文件、保存到数据库这种操作,这些对所有页面都是通用的。

常用Pipeline

WebMagic中就已经提供了控制台输出、保存到文件、保存为JSON格式的文件几种通用的Pipeline。

Learning summary of Java crawler framework WebMagic

在WebMagic里,一个Spider可以有多个Pipeline,使用Spider.addPipeline()即可增加一个Pipeline。

public static void main(String[] args) { Spider.create(new GithubRepoPageProcessor()) // 初始访问url地址 .addUrl("https://github.com/code4craft") .addPipeline(new JsonFilePipeline("D:\\webmagic\\")) .addPipeline(new FilePipeline("D:\\webmagic\\")) //开启5个线程抓取 .thread(5) //启动爬虫 .run(); }
Copy after login

自定义Pipeline

基本Pipeline模式

在抽取的时候,将需要的数据保存为一个对象

public void process(Page page) { DemoData demoData=new DemoData(); demoData.setName("pipeline") page.putField("demoData", demoData); }
Copy after login

创建自定义Pipeline,在Pipeline中,只要使用即可

@Component public class MyDataPipeline implements Pipeline { @Autowired private DemoService demoService; @Override public void process(ResultItems resultItems, Task task) { // 获取封装好的数据 DemoData demoData= resultItems.get("demoData"); if (demoData!= null) { // 把数据保存到数据库中 this.demoService.save(demoData); } } }
Copy after login

注解模式

注解模式下,WebMagic内置了一个PageModelPipeline

public interface PageModelPipeline { // 传入的是处理好的对象 public void process(T t, Task task); }
Copy after login

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

public static void main(String[] args) { OOSpider.create(Site.me().setSleepTime(1000) , new MyPipeline(), DemoData.class) //.addPageModel(new MyPipeline2(),DemoData2.class) .addUrl("https://github.com/code4craft").thread(5).run(); }
Copy after login

自定义MyPipeline类实现PageModelPipeline

@Component public class MyPipeline implements PageModelPipeline { @Autowired private DemoService demoService; @Override public void process(DemoData demoData, Task task) { if (demoData!= null) { // 把数据保存到数据库中 this.demoService.save(demoData); } } }
Copy after login

推荐学习:《java视频教程

The above is the detailed content of Learning summary of Java crawler framework WebMagic. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:juejin.im
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!