前言
前些天开源了一个基于配置的爬虫webmagicx(https://gitee.com/luosl/webmagicx),没想到还有不少朋友感兴趣,而且都在问文档的事情,于是就有了这篇博客,或者说是webmagicx的文档。
webmagicx是一个基于webmagic(https://gitee.com/flashsword20/webmagic)内核的爬虫,目标是打造一个简单、易用、灵活、的可配置化爬虫。所以配置文件是webmagicx的核心,本篇文章会提供一个快速开始的案例,让读者快速的使用webmagicx;然后会重点围绕着webmagicx的配置文件进行详细说明。
快速开始
使用二进制包开始第一个爬虫
webmagicx提供了可执行的二进制包,免去了编译痛苦,直接下载就可以使用。你只需要以下步骤,就可以启动你的第一个爬虫:
- 首先你需要安装jdk1.8以上。
- 点击此处下载webmagicx二进制包
- 解压zip包,运行start.bat,或者在当前目录执行命令 java -jar webmagicx-1.0-SNAPSHOT.jar
- 待爬虫运行一段时间后会在当前目录生成 test.csv 文件,文件内便是爬虫抓取的信息。
- 打开浏览器,输入网址http://localhost:9000/spider/osc.spider,即可看到爬虫的运行状态,如下图所示:
webmagicx二进制包的结构
webmagicx的二进制包解压后会得到如下的一些文件:
webmagicx └ spiderConf → 爬虫配置文件目录,用于存放爬虫配置文件 └ osc.spider.xml → 爬虫配置文件,请放到格式为xml,请放到spiderConf目录下,请务必以.spider.xml结尾 └ start.bat → windos环境下,快捷启动命令,可用 java -jar webmagicx-1.0-SNAPSHOT.jar 命令代替 └ webmagicx-1.0-SNAPSHOT.jar → webmagicx二进制jar包
webmagicx的配置详解
对于webmagicx来说,爬虫配置文件是一个及其重要的组成部分,它描述了一个爬虫的抓取、解析,存储、调度等各个生命周期。对于一份完整的配置文件,它应该有以下几个部分:
- startUrls:爬虫url入口。
- desc:爬虫的描述信息
- task:爬虫的定时调度
- targetUrlRegexs:爬虫到底抓那些网页?
- attribute:爬虫的属性,比如开几个线程,抓多深的深度等。
- components:爬虫的组件,一般情况下,我们只需要定义pipeline,用来告诉爬虫怎么保存抓取的结果。
- site:站点配置,主要是用来伪装爬虫。
- fields:抓取的字段配置。
startUrls标签
startUrls标签是用来描述爬虫的入口url地址。你可以通过url子标签来配置一个或多个startUrl。
<startUrls>
<url>https://www.oschina.net/blog</url>
<url>https://www.oschina.net/blog?classification=428612</url>
</startUrls>
desc标签
desc标签不是一个必须标签,他主目的主要是描述爬虫任务。
<desc>抓取开源中国博客的标题和作者</desc>
task标签
task标签主要是用来描述爬虫的定时调度任务(此时任务类型为corn,目前仅支持corn的调度方式)。task标签的属性startNow可以控制任务是否提交时立刻启动,startNow默认为true。
task标签不是一个必须标签,当没有该标签时,该爬虫任务是一个once(一次性)任务。
<!-- 定时任务配置,当startNow为true,任务会马上启动 -->
<task startNow="true" corn="0 0 */1 * * ?" />
targetUrlRegexs标签
targetUrlRegex标签,用来定义抽取页面中url的正则表达式组。用子标签regex来定义单个正则表达式,regex标签的属性xpath,可以限定该正则表达式的抽取范围。可以配置多个regex标签。
<targetUrlRegexs>
<!-- xpath可以限定目标url的抽取范围 -->
<regex xpath="//*section[@class='box-aw']">https://my\.oschina\.net/[a-z0-9A-Z]+/blog.*</regex>
</targetUrlRegexs>
attribute标签
attribute标签定义了爬虫的属性,当前支持一下属性:
- maxDeep,爬虫抓取的最大深度。当取值为-1则不限定深度。深度的规则为,从startUrls中的配置的url开始深度为0,从startUrl页面中提取的url深度则为1,随后依次递增。当不配置该属性时默认为-1。
- charset,字符集,默认为utf-8。
- timeout,超时时间,默认为20000。
- threadNum,线程数,默认为1。
- retryTimes,下载失败后的重试次数,默认为0。
- sleep,每抓取一个网页后的睡眠时间,默认为1000毫秒
<attribute>
<!-- 最大抓取深度,默认为-1 -->
<maxDeep>1</maxDeep>
<!-- 字符集,默认为UTF-8 -->
<charset>UTF-8</charset>
<!-- 超时(毫秒),默认为20000 -->
<timeout>20000</timeout>
<!-- 线程数,默认为1 -->
<threadNum>15</threadNum>
<!-- 抓取失败后的重试次数,默认为0 -->
<retryTimes>0</retryTimes>
<!-- 每次抓取后的睡眠时间,默认为1000 -->
<sleep>1000</sleep>
</attribute>
components标签
components标签,定义了爬虫的组件,当前爬虫定义了processor,scheduler,handler,pipeline四种组件标签,分别用于页面字段抽取、url管理、抓取后的数据清洗、存储。在webmagic组件中,每个组件标签都有class和props用来描述组件的全类名和属性信息。各个组件的的情况如下:
- processor,页面处理器,该组件仅能配置一个,用于解析、抽取网页中的字段信息。默认为org.luosl.webmagicx.processor.GeneralProcessor,除非用特定需求,否则无需配置该组件。
- scheduler,调度器,该组件仅能配置一个,用于管理url的组件,它主要是用来对待抓取的URL队列进行管理和对已抓取的URL进行去重。默认为org.luosl.webmagicx.scheduler.QueueScheduler,目前webmagicx仅实现了基于内存的scheduler。
- handler,字段处理器,该组可以配置多个,主要用于对抓取结果的清洗,属于定制组件。目前暂无实现。
- pipeline,抓取字段的保存管道,可以配置多个,用于保存爬虫抓取的结果。目前实现基于文件(csv)和基于数据库通用管道。
对于以上4种组件,我们仅仅配置pipeline组件就行(其他组件目前没有其他实现),应为它定义了抓取数据的存储。在当前版本中,实现了基于文件(csv)的的管道和基于数据库的管道他们的配置信息如下:
CSVPipeline
CSVPipeline是将数据保存到csv文件中的pipeline。
<!-- csv管道 -->
<pipeline>
<!-- 当前管道的全类名 -->
<class>org.luosl.webmagicx.pipeline.CSVPipeline</class>
<props>
<!-- 写模式,目前支持override和append,分别代表覆盖和追加 -->
<model value="override"/>
<charset value="gb2312" />
<!-- 用来进行去重的字段,非必须,在程序中内置[_url,_page]两个字段,分别表示当前url,和当前页面 -->
<distinctField value="_url"/>
<!-- 需要保存的字段,*表示所有字段 -->
<needSaveFields value="_url,title,author"/>
<!-- 在爬虫任务终止时是否需要关闭csv文件,当任务为一次性时请设置为true,为调度任务时,设置为false -->
<closeAtTheEnd value="false" />
<!-- 保存的csv路径 -->
<path value="osc_blog.csv"/>
</props>
</pipeline>
SimpleJdbcPipeline
SimpleJdbcPipeline是将数据保存到数据库的pipeline,需要注意的是,当配置的表在数据库中不存在时,该管道会自动创建类型为text的数据表。
<!-- jdbc管道 -->
<pipeline>
<!-- 当前管道的全类名 -->
<class>org.luosl.webmagicx.pipeline.SimpleJdbcPipeline</class>
<props>
<!-- 写模式,当前支持override和append,分别代表覆盖和追加 -->
<model value="append"/>
<!-- 用来进行去重的字段,在 程序中内置[_url,_page]两个字段,分别表示当前url,和当前页面 -->
<distinctField value="url"/>
<!-- 需要保存的字段,*表示所有字段 -->
<needSaveFields value="_url,title,author"/>
<!-- 数据库驱动 -->
<driver value="com.mysql.jdbc.Driver"/>
<!-- 数据库url -->
<url>jdbc:mysql://localhost/spider?useUnicode=true&characterEncoding=UTF-8</url>
<!-- 数据库用户名 -->
<user value="root"/>
<!-- 数据库密码 -->
<password value="123456"/>
<!-- 数据库表名称 -->
<tableName value="tb_osc"/>
</props>
</pipeline>
site标签
site标签主要是用来定义一些关于站点的信息来伪装爬虫,它有userAgent,headers,cookies三个子标签分别用于定义浏览器标识、请求头和cookie。
<!-- 站点配置 -->
<site>
<!-- 浏览器标识 -->
<userAgent>Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36</userAgent>
<!-- 请求头 -->
<headers>
<header key="authority" value="www.oschina.net" />
</headers>
<!-- cookie -->
<cookies>
<cookie key="cookie" value="cookieValue"/>
</cookies>
</site>
fields标签
fields标签是用来定义字段抽取规则组,fields标签下的filed标签用来定义单个字段的抽取规则。在filed标签下有如下几个子标签:
- name,字段名称。
- xpath,字段抽取的xpath表达式
- xpaths,当一个字段存在多个xpath表达式时,需要用到该标签,它的scope属性表示对所有xpath抽取到的数据的取值范围,scope属性有3个取值,分别是:head,last,all;分别表示:取第一个有效值;取最后一个有效值,取所有有效值。
- textFormat,是否将抽取到的数据做文本格式化(也就是是否剔除文本中的html标签)。
- must,是否为必须字段,当为true时,若该字段未抓取到值,不会被pipelne处理。
<!-- 抓取字段配置 -->
<fields>
<field>
<!-- 字段名称 -->
<name>author</name>
<!-- 抽取html的xpath表达式 -->
<xpath>//*div[@class='user-info']/div[@class='name']/a/text()</xpath>
<!-- 是否将抽取后的数据格式化为纯文本(剔除html标签) -->
<textFormat>true</textFormat>
<!-- 是否为必须字段,当为true时,若该字段未抓取到值,不会被pipelne处理 -->
<must>true</must>
</field>
<field>
<!-- 字段名称 -->
<name>title</name>
<!--
一个字段有多个xpath表达式的写法,属性scope取值为head,last,all;
分别表示:取第一个有效值;取最后一个有效值,取所有有效值。
-->
<xpaths scope="head">
<xpath>//*div[@class='title']/text()</xpath>
<!--<xpath>//*div[@class='title']/text()</xpath>-->
</xpaths>
<textFormat>true</textFormat>
<must>true</must>
</field>
</fields>