java 爬虫 WebMagic-使用入门

2024-04-10 16:18

本文主要是介绍java 爬虫 WebMagic-使用入门,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文出自:http://webmagic.io/docs/zh
http://blog.csdn.net/u013510614/article/details/50313835
在WebMagic里,实现一个基本的爬虫只需要编写一个类,实现PageProcessor接口即可。这个类基本上包含了抓取一个网站,你需要写的所有代码。

同时这部分还会介绍如何使用WebMagic的抽取API,以及最常见的抓取结果保存的问题。

实现PageProcessor
这部分我们直接通过GithubRepoPageProcessor这个例子来介绍PageProcessor的编写方式。我将PageProcessor的定制分为三个部分,分别是爬虫的配置、页面元素的抽取和链接的发现。

public class GithubRepoPageProcessor implements PageProcessor {

// 部分一:抓取网站的相关配置,包括编码、抓取间隔、重试次数等
private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);@Override
// process是定制爬虫逻辑的核心接口,在这里编写抽取逻辑
public void process(Page page) {// 部分二:定义如何抽取页面信息,并保存下来page.putField("author", page.getUrl().regex("https://github\\.com/(\\w+)/.*").toString());page.putField("name", page.getHtml().xpath("//h1[@class='entry-title public']/strong/a/text()").toString());if (page.getResultItems().get("name") == null) {//skip this pagepage.setSkip(true);}page.putField("readme", page.getHtml().xpath("//div[@id='readme']/tidyText()"));// 部分三:从页面发现后续的url地址来抓取page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/\\w+/\\w+)").all());
}@Override
public Site getSite() {return site;
}public static void main(String[] args) {Spider.create(new GithubRepoPageProcessor())//从"https://github.com/code4craft"开始抓.addUrl("https://github.com/code4craft")//开启5个线程抓取.thread(5)//启动爬虫.run();
}

}
爬虫的配置
第一部分关于爬虫的配置,包括编码、抓取间隔、超时时间、重试次数等,也包括一些模拟的参数,例如User Agent、cookie,以及代理的设置,我们会在第5章-“爬虫的配置”里进行介绍。在这里我们先简单设置一下:重试次数为3次,抓取间隔为一秒。

页面元素的抽取
第二部分是爬虫的核心部分:对于下载到的Html页面,你如何从中抽取到你想要的信息?WebMagic里主要使用了三种抽取技术:XPath、正则表达式和CSS选择器。另外,对于JSON格式的内容,可使用JsonPath进行解析。

XPath

XPath本来是用于XML中获取元素的一种查询语言,但是用于Html也是比较方便的。例如:

page.getHtml().xpath(“//h1[@class=’entry-title public’]/strong/a/text()”)
这段代码使用了XPath,它的意思是“查找所有class属性为’entry-title public’的h1元素,并找到他的strong子节点的a子节点,并提取a节点的文本信息”。 对应的Html是这样子的:

xpath-html

CSS选择器

CSS选择器是与XPath类似的语言。如果大家做过前端开发,肯定知道$(‘h1.entry-title’)这种写法的含义。客观的说,它比XPath写起来要简单一些,但是如果写复杂一点的抽取规则,就相对要麻烦一点。

正则表达式

正则表达式则是一种通用的文本抽取语言。

page.addTargetRequests(page.getHtml().links().regex(“(https://github\.com/\w+/\w+)”).all());
这段代码就用到了正则表达式,它表示匹配所有”https://github.com/code4craft/webmagic“这样的链接。

JsonPath

JsonPath是于XPath很类似的一个语言,它用于从Json中快速定位一条内容。WebMagic中使用的JsonPath格式可以参考这里:https://code.google.com/p/json-path/

链接的发现
有了处理页面的逻辑,我们的爬虫就接近完工了!

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

page.addTargetRequests(page.getHtml().links().regex(“(https://github\.com/\w+/\w+)”).all());
这段代码的分为两部分,page.getHtml().links().regex(“(https://github\.com/\w+/\w+)”).all()用于获取所有满足”(https:/ /github.com/\w+/\w+)”这个正则表达式的链接,page.addTargetRequests()则将这些链接加入到待抓取的队列中去。

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

在刚才的例子中可以看到,page.getHtml()返回的是一个Html对象,它实现了Selectable接口。这个接口包含一些重要的方法,我将它分为两类:抽取部分和获取结果部分。

抽取部分API:
方法 说明 示例
xpath(String xpath) 使用XPath选择 html.xpath(“//div[@class=’title’]”)
(Stringselector)使Csshtml. (“div.title”)
(Stringselector,Stringattr)使Csshtml. (“div.title”,”text”)
css(String selector) 功能同$(),使用Css选择器选择 html.css(“div.title”)
links() 选择所有链接 html.links()
regex(String regex) 使用正则表达式抽取 html.regex(“\
(.*?)\”)
regex(String regex,int group) 使用正则表达式抽取,并指定捕获组 html.regex(“\
(.*?)\”,1)
replace(String regex, String replacement) 替换内容 html.replace(“\”,”“)
这部分抽取API返回的都是一个Selectable接口,意思是说,抽取是支持链式调用的。下面我用一个实例来讲解链式API的使用。

例如,我现在要抓取github上所有的Java项目,这些项目可以在https://github.com/search?l=Java&p=1&q=stars%3A%3E1&s=stars&type=Repositories搜索结果中看到。

为了避免抓取范围太宽,我指定只从分页部分抓取链接。这个抓取规则是比较复杂的,我会要怎么写呢?

selectable-chain-ui

首先看到页面的html结构是这个样子的:

selectable-chain

那么我可以先用CSS选择器提取出这个div,然后在取到所有的链接。为了保险起见,我再使用正则表达式限定一下提取出的URL的格式,那么最终的写法是这样子的:

List urls = page.getHtml().css(“div.pagination”).links().regex(“./search/\?l=java.“).all();
然后,我们可以把这些URL加到抓取列表中去:

List urls = page.getHtml().css(“div.pagination”).links().regex(“./search/\?l=java.“).all();
page.addTargetRequests(urls);
是不是比较简单?除了发现链接,Selectable的链式抽取还可以完成很多工作。我们会在第9章示例中再讲到。

获取结果的API:
当链式调用结束时,我们一般都想要拿到一个字符串类型的结果。这时候就需要用到获取结果的API了。我们知道,一条抽取规则,无论是XPath、CSS选择器或者正则表达式,总有可能抽取到多条元素。WebMagic对这些进行了统一,你可以通过不同的API获取到一个或者多个元素。

方法 说明 示例
get() 返回一条String类型的结果 String link= html.links().get()
toString() 功能同get(),返回一条String类型的结果 String link= html.links().toString()
all() 返回所有抽取结果 List links= html.links().all()
match() 是否有匹配结果 if (html.links().match()){ xxx; }
例如,我们知道页面只会有一条结果,那么可以使用selectable.get()或者selectable.toString()拿到这条结果。

这里selectable.toString()采用了toString()这个接口,是为了在输出以及和一些框架结合的时候,更加方便。因为一般情况下,我们都只需要选择一个元素!

selectable.all()则会获取到所有元素。

好了,到现在为止,在回过头看看3.1中的GithubRepoPageProcessor,可能就觉得更加清晰了吧?指定main方法,已经可以看到抓取结果在控制台输出了。

保存结果
好了,爬虫编写完成,现在我们可能还有一个问题:我如果想把抓取的结果保存下来,要怎么做呢?WebMagic用于保存结果的组件叫做Pipeline。例如我们通过“控制台输出结果”这件事也是通过一个内置的Pipeline完成的,它叫做ConsolePipeline。那么,我现在想要把结果用Json的格式保存下来,怎么做呢?我只需要将Pipeline的实现换成”JsonFilePipeline”就可以了。

public static void main(String[] args) {
Spider.create(new GithubRepoPageProcessor())
//从”https://github.com/code4craft“开始抓
.addUrl(“https://github.com/code4craft“)
.addPipeline(new JsonFilePipeline(“D:\webmagic\”))
//开启5个线程抓取
.thread(5)
//启动爬虫
.run();
}
这样子下载下来的文件就会保存在D盘的webmagic目录中了。

通过定制Pipeline,我们还可以实现保存结果到文件、数据库等一系列功能。这个会在第7章“抽取结果的处理”中介绍。

至此为止,我们已经完成了一个基本爬虫的编写,也具有了一些定制功能。

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

方法 说明 示例
create(PageProcessor) 创建Spider Spider.create(new GithubRepoProcessor())
addUrl(String…) 添加初始的URL spider .addUrl(“http://webmagic.io/docs/“)
addRequest(Request…) 添加初始的Request spider .addRequest(“http://webmagic.io/docs/“)
thread(n) 开启n个线程 spider.thread(5)
run() 启动,会阻塞当前线程执行 spider.run()
start()/runAsync() 异步启动,当前线程继续执行 spider.start()
stop() 停止爬虫 spider.stop()
test(String) 抓取一个页面进行测试 spider .test(“http://webmagic.io/docs/“)
addPipeline(Pipeline) 添加一个Pipeline,一个Spider可以有多个Pipeline spider .addPipeline(new ConsolePipeline())
setScheduler(Scheduler) 设置Scheduler,一个Spider只能有个一个Scheduler spider.setScheduler(new RedisScheduler())
setDownloader(Downloader) 设置Downloader,一个Spider只能有个一个Downloader spider .setDownloader(new SeleniumDownloader())
get(String) 同步调用,并直接取得结果 ResultItems result = spider .get(“http://webmagic.io/docs/“)
getAll(String…) 同步调用,并直接取得一堆结果 List results = spider .getAll(“http://webmagic.io/docs/“, “http://webmagic.io/xxx“)
Site
对站点本身的一些配置信息,例如编码、HTTP头、超时时间、重试策略等、代理等,都可以通过设置Site对象来进行配置。

方法 说明 示例
setCharset(String) 设置编码 site.setCharset(“utf-8”)
setUserAgent(String) 设置UserAgent site.setUserAgent(“Spider”)
setTimeOut(int) 设置超时时间,单位是毫秒 site.setTimeOut(3000)
setRetryTimes(int) 设置重试次数 site.setRetryTimes(3)
setCycleRetryTimes(int) 设置循环重试次数 site.setCycleRetryTimes(3)
addCookie(String,String) 添加一条cookie site.addCookie(“dotcomt_user”,”code4craft”)
setDomain(String) 设置域名,需设置域名后,addCookie才可生效 site.setDomain(“github.com”)
addHeader(String,String) 添加一条addHeader site.addHeader(“Referer”,”https://github.com“)
setHttpProxy(HttpHost) 设置Http代理 site.setHttpProxy(new HttpHost(“127.0.0.1”,8080))
其中循环重试cycleRetry是0.3.0版本加入的机制。

该机制会将下载失败的url重新放入队列尾部重试,直到达到重试次数,以保证不因为某些网络原因漏抓页面。

抽取工具简介
WebMagic的抽取主要用到了Jsoup和我自己开发的工具Xsoup。

Jsoup
Jsoup是一个简单的HTML解析器,同时它支持使用CSS选择器的方式查找元素。为了开发WebMagic,我对Jsoup的源码进行过详细的分析,具体文章参见Jsoup学习笔记。

Xsoup
Xsoup是我基于Jsoup开发的一款XPath解析器。

之前WebMagic使用的解析器是HtmlCleaner,使用过程存在一些问题。主要问题是XPath出错定位不准确,并且其不太合理的代码结构,也难以进行定制。最终我自己实现了Xsoup,使得更加符合爬虫开发的需要。令人欣喜的是,经过测试,Xsoup的性能比HtmlCleaner要快一倍以上。

Xsoup发展到现在,已经支持爬虫常用的语法,以下是一些已支持的语法对照表:

Name Expression Support
nodename nodename yes
immediate parent / yes
parent // yes
attribute [@key=value] yes
nth child tag[n] yes
attribute /@key yes
wildcard in tagname / yes
wildcard in attribute /[@] yes
function function() part
or a | b yes since 0.2.0
parent in path . or .. no
predicates price>35 no
predicates logic @class=a or @class=b yes since 0.2.0
另外我自己定义了几个对于爬虫来说,很方便的XPath函数。但是请注意,这些函数式标准XPath没有的。

Expression Description XPath1.0
text(n) 第n个直接文本子节点,为0表示所有 text() only
allText() 所有的直接和间接文本子节点 not support
tidyText() 所有的直接和间接文本子节点,并将一些标签替换为换行,使纯文本显示更整洁 not support
html() 内部html,不包括标签的html本身 not support
outerHtml() 内部html,包括标签的html本身 not support
regex(@attr,expr,group) 这里@attr和group均可选,默认是group0 not support
Saxon
Saxon是一个强大的XPath解析器,支持XPath 2.0语法。webmagic-saxon是对Saxon尝试性的一个整合,但是目前看来,XPath 2.0的高级语法,似乎在爬虫开发中使用者并不多。

爬虫的监控
爬虫的监控是0.5.0新增的功能。利用这个功能,你可以查看爬虫的执行情况——已经下载了多少页面、还有多少页面、启动了多少线程等信息。该功能通过JMX实现,你可以使用Jconsole等JMX工具查看本地或者远程的爬虫信息。

如果你完全不会JMX也没关系,因为它的使用相对简单,本章会比较详细的讲解使用方法。如果要弄明白其中原理,你可能需要一些JMX的知识,推荐阅读:JMX整理。我很多部分也对这篇文章进行了参考。

注意: 如果你自己定义了Scheduler,那么需要用这个类实现MonitorableScheduler接口,才能查看“LeftPageCount”和“TotalPageCount”这两条信息。

为项目添加监控
添加监控非常简单,获取一个SpiderMonitor的单例SpiderMonitor.instance(),并将你想要监控的Spider注册进去即可。你可以注册多个Spider到SpiderMonitor中。

public class MonitorExample {

public static void main(String[] args) throws Exception {Spider oschinaSpider = Spider.create(new OschinaBlogPageProcessor()).addUrl("http://my.oschina.net/flashsword/blog");Spider githubSpider = Spider.create(new GithubRepoPageProcessor()).addUrl("https://github.com/code4craft");SpiderMonitor.instance().register(oschinaSpider);SpiderMonitor.instance().register(githubSpider);oschinaSpider.start();githubSpider.start();
}

}
查看监控信息
WebMagic的监控使用JMX提供控制,你可以使用任何支持JMX的客户端来进行连接。我们这里以JDK自带的JConsole为例。我们首先启动WebMagic的一个Spider,并添加监控代码。然后我们通过JConsole来进行查看。

我们按照4.6.1的例子启动程序,然后在命令行输入jconsole(windows下是在DOS下输入jconsole.exe)即可启动JConsole。

jconsole

这里我们选择启动WebMagic的本地进程,连接后选择“MBean”,点开“WebMagic”,就能看到所有已经监控的Spider信息了!

这里我们也可以选择“操作”,在操作里可以选择启动-start()和终止爬虫-stop(),这会直接调用对应Spider的start()和stop()方法,来达到基本控制的目的。

jconsole-show

扩展监控接口
除了已有的一些监控信息,如果你有更多的信息需要监控,也可以通过扩展的方式来解决。你可以通过继承SpiderStatusMXBean来实现扩展,具体例子可以看这里: 定制扩展demo。

这篇关于java 爬虫 WebMagic-使用入门的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/891540

相关文章

C语言中联合体union的使用

本文编辑整理自: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=179471 一、前言 “联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量

Java五子棋之坐标校正

上篇针对了Java项目中的解构思维,在这篇内容中我们不妨从整体项目中拆解拿出一个非常重要的五子棋逻辑实现:坐标校正,我们如何使漫无目的鼠标点击变得有序化和可控化呢? 目录 一、从鼠标监听到获取坐标 1.MouseListener和MouseAdapter 2.mousePressed方法 二、坐标校正的具体实现方法 1.关于fillOval方法 2.坐标获取 3.坐标转换 4.坐

Spring Cloud:构建分布式系统的利器

引言 在当今的云计算和微服务架构时代,构建高效、可靠的分布式系统成为软件开发的重要任务。Spring Cloud 提供了一套完整的解决方案,帮助开发者快速构建分布式系统中的一些常见模式(例如配置管理、服务发现、断路器等)。本文将探讨 Spring Cloud 的定义、核心组件、应用场景以及未来的发展趋势。 什么是 Spring Cloud Spring Cloud 是一个基于 Spring

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

Javascript高级程序设计(第四版)--学习记录之变量、内存

原始值与引用值 原始值:简单的数据即基础数据类型,按值访问。 引用值:由多个值构成的对象即复杂数据类型,按引用访问。 动态属性 对于引用值而言,可以随时添加、修改和删除其属性和方法。 let person = new Object();person.name = 'Jason';person.age = 42;console.log(person.name,person.age);//'J

java8的新特性之一(Java Lambda表达式)

1:Java8的新特性 Lambda 表达式: 允许以更简洁的方式表示匿名函数(或称为闭包)。可以将Lambda表达式作为参数传递给方法或赋值给函数式接口类型的变量。 Stream API: 提供了一种处理集合数据的流式处理方式,支持函数式编程风格。 允许以声明性方式处理数据集合(如List、Set等)。提供了一系列操作,如map、filter、reduce等,以支持复杂的查询和转

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

C++必修:模版的入门到实践

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C++学习 贝蒂的主页:Betty’s blog 1. 泛型编程 首先让我们来思考一个问题,如何实现一个交换函数? void swap(int& x, int& y){int tmp = x;x = y;y = tmp;} 相信大家很快就能写出上面这段代码,但是如果要求这个交换函数支持字符型

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM

详细分析Springmvc中的@ModelAttribute基本知识(附Demo)

目录 前言1. 注解用法1.1 方法参数1.2 方法1.3 类 2. 注解场景2.1 表单参数2.2 AJAX请求2.3 文件上传 3. 实战4. 总结 前言 将请求参数绑定到模型对象上,或者在请求处理之前添加模型属性 可以在方法参数、方法或者类上使用 一般适用这几种场景: 表单处理:通过 @ModelAttribute 将表单数据绑定到模型对象上预处理逻辑:在请求处理之前