WebCollector内核解析—如何设计一个爬虫

本文利用WebCollector内核的解析,来描述如何设计一个网络爬虫。我们先来看看两个非常优秀爬虫的设计。

Nutch

Nutch由apache开源组织提供,主页:http://nutch.apache.org/

Nutch是目前最好的网络爬虫之一,Nutch分为内核和插件两个模块组成,内核控制整个爬取的逻辑,插件负责完成每个细节(与流程无关的细节)的实现。具体分工如下:

内核:控制爬虫按照 Inject -> Generator -> Fetch -> Parse -> Updatedb ( -> 提交索引(可选))的流程进行,而且这些流程都是利用map reduce在hadoop上实现的。

插件:实现爬虫的http请求、解析器、URL过滤器、索引等细节功能。

Nutch的内核提供了稳定的可在集群上运行的爬取机制(广度遍历),插件为爬虫提供了强大的扩展能力。

Crawler4j

Crawler4j由Yasser Ganjisaffar(微软bing的一位工程师)提供,项目主页:https://code.google.com/p/crawler4j/

用Crawler4j写爬虫,用户只需要指定两处:

1) 爬虫的种子、线程数等配置

2)覆盖WebCrawler类的visit(Page page)方法,对每个页面的自定义操作(抽取、存储)

这使得爬虫的二次开发大大简化,只需要定制两处,即可定制一个完成下载/精抽取功能的爬虫。python爬虫scrapy也是采用这种机制。

Nutch是被设计在hadoop上的,而且插件的调度以反射的形式实现,所以它的插件机制,并不如想象的那样灵活。写一个插件需要附带几个配置文件,并修改Nutch总配置文件。而且Nutch其实是为了搜索引擎定制的,所以NUTCH提供的挂载点,并不能做精抽取之类的业务提供很好的扩展。

Crwler4j虽然提供精简的用户接口,但是并没有一套插件机制,来定制自己的爬虫。例如用Crawler4j来爬取新浪微博,就需要修改源码,来完成对新浪微博的模拟登陆。

WebCollector

主页:https://github.com/CrawlScript/WebCollector

WebCollector使用了Nutch的爬取逻辑(分层广度遍历),Crawler4j的的用户接口(覆盖visit方法,定义用户操作),以及一套自己的插件机制,设计了一套爬虫内核。

WebCollector内核构架图:

CrawlDB: 任务数据库,爬虫的爬取任务(类似URL列表)是存放在CrawlDB中的,CrawlDB根据DbUpdater和Generator所选插件不同,可以有多种形式,如文件、redis、mysql、mongodb等。

Injector: 种子注入器,负责第一轮爬取时,向CrawlDB中提交爬取任务。在断点续爬的时候,不需要通过Injector向CrawlDB注入种子,因为CrawlDB中已有爬取任务。

Generator: 任务生成器,任务生成器从CrawlDB获取爬取任务,并进行过滤(正则、爬取间隔等),将任务提交给抓取器。

Fetcher: 抓取器,Fetcher是爬虫最核心的模块,Fetcher负责从Generator中获取爬取任务,用线程池来执行爬取任务,并对爬取的网页进行链接解析,将链接信息更新到CrawlDB中,作为下一轮的爬取任务。在网页被爬取成功/失败的时候,Fetcher会将网页和相关信息以消息的形式,发送到Handler的用户自定义模块,让用户自己处理网页内容(抽取、存储)。

DbUpdater: 任务更新器,用来更新任务的状态和加入新的任务,网页爬取成功后需要更新CrawlDB中的状态,对网页做解析,发现新的连接,也需要更新CrawlDB。

Handler: 消息发送/处理器,Fetcher利用Handler把网页信息打包,发送到用户自定义操作模块。

User Defined Operation: 用户自定义的对网页信息进行处理的模块,例如网页抽取、存储。爬虫二次开发主要就是自定义User Defined Operation这个模块。实际上User Defined Operation也是在Handler里定义的。

RequestFactory: Http请求生成器,通过RequestFactory来选择不同的插件,来生成Http请求,例如可以通过httpclient插件来使用httpclient作为爬虫的http请求,或者来使用可模拟登陆新浪微博的插件,来发送爬取新浪微博的http请求。

ParserFactory: 用来选择不同的链接分析器(插件)。爬虫之所以可以从一个网页开始,向多个网页不断地爬取,就是因为它在不断的解析已知网页中的链接,来发现新的未知网页,然后对新的网页进行同样的操作。

爬取逻辑:

WebCollector和Nutch一样,把爬虫的广度遍历拆分成了分层的操作。

第一层:爬取一个网页,http://www.apache.org/,解析网页,获取3个链接,将3个链接保存到CrawlDB中,设置状态为未爬取。同时将http://www.apache.org/的爬取状态设置为已爬取。结束第一轮。

第二层,找到CrawlDB中状态为未爬取的页面(第一层解析出来的3个链接),分别爬取,并解析网页,一共获得8个链接。和第一层操作一样,将解析出的链接放入CrawlDB,设置为未爬取,并将第二层爬取的三个页面,状态设置为已爬取。

第三层,找到CrawlDB中状态为未爬取的页面(第二层解析出来的8个链接).................

每一层都可以作为一个独立的任务去运行,所以可以将一个大型的广度遍历任务,拆分成一个一个小任务。爬虫里有个参数,设置爬取的层数,指的就是这个。

插件机制:

框架图中的 Injector、Generator、Request(由RequestFactory生成)、Parser(由ParserFactory生成)、DbUpdater、Response都是以插件实现的。制作插件往往只需要自定义一个实现相关接口的类,并在相关Factory内指定即可。

WebCollector内置了一套插件(cn.edu.hfut.dmic.webcollector.plugin.redis)。基于这套插件,可以把WebCollector的任务管理放到redis数据库上,这使得WebCollector可以爬取海量的数据(上亿级别)。

用户自定义操作:

对于用户来说,关注的更多的不是爬虫的爬取流程,而是对每个网页要进行什么样的操作。对网页进行抽取、保存还是其他操作,应该是由用户自定义的。

假设我们有个需求,要爬取《知乎》上的所有提问。对用户来说,只需要定义对知乎的提问如何抽取。

public class ZhihuCrawler extends BreadthCrawler{

    /*visit函数定制访问每个页面时所需进行的操作*/
    @Override
    public void visit(Page page) {
        String question_regex="^http://www.zhihu.com/question/[0-9]+";
        if(Pattern.matches(question_regex, page.getUrl())){
            System.out.println("正在抽取"+page.getUrl());
            /*抽取标题*/
            String title=page.getDoc().title();
            System.out.println(title);
            /*抽取提问内容*/
            String question=page.getDoc().select("div[id=zh-question-detail]").text();
            System.out.println(question);

        }
    }

    /*启动爬虫*/
    public static void main(String[] args) throws IOException{
        ZhihuCrawler crawler=new ZhihuCrawler();
        crawler.addSeed("http://www.zhihu.com/question/21003086");
        crawler.addRegex("http://www.zhihu.com/.*");
        crawler.start(5);
    }

}

覆盖BreadthCrawler类的visit方法,即可实现用户自定义操作,完全不用考虑爬虫的爬取逻辑。

WebCollector的设计主要来自于Nutch,相当于将Nutch抽象成了一个爬虫内核。

最后再次附上项目地址:https://github.com/CrawlScript/WebCollector

时间: 2024-10-14 08:16:15

WebCollector内核解析—如何设计一个爬虫的相关文章

设计网路爬虫过程中需要注意的解析问题

现在爬虫工作者越来越多,那么今天就讲讲就从解析数据和模拟器好好说说爬虫. 原本的称呼就是应该是叫解析网页,但是目前移动数据已经成为日常生活中不可或缺的数据走向,所以解析数据这个词来形容 会更加精准,解析数据.解析数据就是说当我们访问一个网址的时候,服务器就该网站把内容反馈给了我,我应该如何的把我 真正需要的数据提取出来.当服务器返回给我们的是html的时候,我需要提取到具体哪个 DIV 下面的内容;当服务器返回给我 的是 XML 时,我也需要提取某个标签下面的内容. 我们采用的最原始的方式就是使

从研发人的角度评判怎样设计一个好的DCS系统

相信从事自动化或控制系统的同仁,应该了解Distributed Control System(简称DCS)的基本功能及其在工控行业的作用.从工程应用的角度,一个完整的DCS系统主要包括三个部分:HMI人机交互层.控制站层.仪表与执行机构层. HMI主要包括工程师站.监控站.历史站等,主要在具有较高稳定的PC上安装相应的软件构成.控制站层,主要实现相应的控制算法与逻辑,并通过相应的IO卡件采集数据和发送指令.仪表与执行机构,主要由各个厂家的智能变送器.电动机等组成. 由于仪表与执行机构,厂家众多,

如何设计一个RPC系统

版权声明:本文由韩伟原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/162 来源:腾云阁 https://www.qcloud.com/community RPC是一种方便的网络通信编程模型,由于和编程语言的高度结合,大大减少了处理网络数据的复杂度,让代码可读性也有可观的提高.但是RPC本身的构成却比较复杂,由于受到编程语言.网络模型.使用习惯的约束,有大量的妥协和取舍之处.本文就是通过分析几种流行的RPC实现案例,提供

Storm【实践系列-如何写一个爬虫】 - ParserBolt

阅读背景: 如果您对爬虫,或则web前端不够了解,请自行google. 代码前提:您需要参阅本ID 所写的前面两篇博文:  Storm[实践系列-如何写一个爬虫] - Fetcher 本章主题: ParserBolt 如何完成的解析,并且如何从前面的组件得到数据,并emit出去. 博文流程:  博文将整个 爬虫系列公开,其过程为: 1 : 代码实现. 2 : 对代码的细节进行解析. 3 : 对真个设计进行回顾,并作总结. 如果您在参看本ID的博文的过程之中,只存在流程 1.那么请继续等待.一旦公

2017-2018-1 20179205《Linux内核原理与设计》第九周作业

<Linux内核原理与设计>第九周作业 视频学习及代码分析 一.进程调度时机与进程的切换 不同类型的进程有不同的调度需求,第一种分类:I/O-bound 会频繁的进程I/O,通常会花费很多时间等待I/O操作的完成:CPU-bound 是计算密集型,需要大量的CPU时间进行运算,使得其他交互式进程反应迟钝,因此需要不同的算法来使系统的运行更高效,以及CPU的资源最大限度的得到使用.第二种分类包括批处理进程(batch process):实时进程(real-time process)以及交互式进程

2017-2018-1 《Linux内核原理与设计》第十二周作业

<linux内核原理与设计>第十二周作业 Sql注入基础原理介绍 分组: 和20179215袁琳完成实验 一.实验说明 ??SQL注入攻击通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,本章课程通过 LAMP 搭建 Sql 注入环境,两个实验分别介绍 Sql 注入爆破数据库.Sql 注入绕过验证两个知识点. 首先通过下面命令将代码下载到实验楼环境中,作为参照对比进行学习. $ wget http://labfil

如何设计一个 RPC 系统

本文由云+社区发表 RPC是一种方便的网络通信编程模型,由于和编程语言的高度结合,大大减少了处理网络数据的复杂度,让代码可读性也有可观的提高.但是RPC本身的构成却比较复杂,由于受到编程语言.网络模型.使用习惯的约束,有大量的妥协和取舍之处.本文就是通过分析几种流行的RPC实现案例,提供大家在设计RPC系统时的参考. 由于RPC底层的网络开发一般和具体使用环境有关,而编程实现手段也非常多样化,但不影响使用者,因此本文基本涉及如何实现一个RPC系统. 认识 RPC (远程调用) 我们在各种操作系统

设计一个 iOS 控件

代码的等级:可编译.可运行.可测试.可读.可维护.可复用 前言 一个控件从外在特征来说,主要是封装这几点: 交互方式 显示样式 数据使用 对外在特征的封装,能让我们在多种环境下达到 PM 对产品的要求,并且提到代码复用率,使维护工作保持在一个相对较小的范围内:而一个好的控件除了有对外一致的体验之外,还有其内在特征: 灵活性 低耦合 易拓展 易维护 通常特征之间需要做一些取舍,比如灵活性与耦合度,有时候接口越多越能适应各种环境,但是接口越少对外产生的依赖就越少,维护起来也更容易.通常一些前期看起来

入门产品经理如何分析设计一个产品

(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:今天的内容是我的一个简单总结,希望让没有任何经验的入门产品经理对产品设计和需求分析有一个大致的了解.当然由于是我自己的心得体会,所以未必是正确和最有效的. 如何设计一个产品,并对其进行需求分析,实际上有很多著作供我们学习和参考.从学院派的<软件需求>,到创业派的<启示录:打造用户喜爱的产品>,还有鸡汤派的<人人都是产品经理>,都值得我们一读.诚然通过阅读经典