剖析NUTCH爬虫

牛顿先生告诉我们,如果想看的远,那就得站到巨人的肩膀上。所以,在自己动手之前,前辈们的研究成果不能不先看看。在网上搜索并整理了一下,发现关于NUTCH的中文学习资料或者说是心得真的不多,其中大部分还都是关注于怎么安装配置上面,稍微深入一点的东西就只能看英文的了。看英文对于大家来说当然难度也不是很大,但是比起中文来终究是有点费时费力。所以我在学习NUTCH的过程中顺手整理了一些看过的资料,一是给自己留点备注,二是拿出来和大家讨论学习。中间出于水平原因,难免有什么纰漏,欢迎大家批评指正。J

剖析NUTCH爬虫——原文出处:Dissecting The Nutch Crawler

1.       简介
开源项目NUTCH搜索引擎大致包括三个部分:
(1)    爬虫:寻找并抓取网页
(2)    网页库:存储已知URL和已抓取网页的数据库
(3)    索引器:解析网页并按照主题字典建立索引

NUTCH 使用多个"bin/nutch"命令脚本进行操作,其中每个脚本命令与一个java类相对应。

对于局域内网页的抓取,你需要首先编写几个配置文件,例如urls.txt和crawl-urlfilter.txt。然后利用"bin/nutch crawl ..."命令进行抓取。这个命令与程序中的net.nutch.tools.CrawlTool类相对应。

对于整个网络网页的抓取,你需要利用下面的命令逐步进行:
$ bin/nutch admin db -create
$ bin/nutch inject db ...
$ bin/nutch generate db segments
$ bin/nutch fetch ...
$ bin/nutch updatedb ...
$ bin/nutch analyze ...

每个命令对应的java类如下所示:

·         admin: net.nutch.tools.WebDBAdminTool

·         inject: net.nutch.db.WebDBInjector

·         generate: net.nutch.tools.FetchListTool

·         fetch: net.nutch.fetcher.Fetcher

·         updatedb: net.nutch.tools.UpdateDatabaseTool

·         analyze: net.nutch.tools.LinkAnalysisTool

可以发现,这些命令利用的是这些java类的类名或者类名简写,举例来说,下面两个命令的含义就是相同的。

$ bin/nutch admin db -create
$ bin/nutch net.nutch.tools.WebDBAdminTool db -create

下面我们可以通过对这些类的分析来了解NUTCH爬虫的工作机制。

3.CRAWL命令:net.nutch.tools.CrawlTool类

CrawlTool类的作用很好理解,它就是将爬行整个网络的一系列命令操作综合在一起并加以限制条件实现了局域性网络的爬行。它主要包括了两个静态函数和一个main函数。下面是操作细节:

    作:                               对应的函数:
- start logger:                        LogFormatter.getLogger(...)
(生成日志文件)                             
- load "crawl-tool.xml" config file:   NutchConf.addConfResource(...)
(加载配置文件)
-        read arguments from command-line
(读取命令行参数,如爬行深度等)
- create a new web db:                   WebDBAdminTool.main(...)
(生成一个新网页库)
- add rootURLs into the db:             WebDBInjector.main(...)
(将种子URL写入网页库)
- for 1 to depth (=5 by default):      
    - generate a new segment:            FetchListTool.main(...)
    - fetch the segment:                  Fetcher.main(...)
- update the db:                     UpdateDatabaseTool.main(...)
(爬行网页并更新网页库)
- comment: 
    "Re-fetch everything to get complete set of incoming anchor texts"
- delete all old segment data:         FileUtil.fullyDelete(...)
- make a single segment with all pages:FetchListTool.main(...)
- re-fetch everything:                    Fetcher.main(...)
(根据网页锚文本爬行链接网页)
- index:                                 IndexSegment.main(...)
(索引)
- dedup:                                 DeleteDuplicates.main(...)
(删除备份)
- merge:                                 IndexMerger.main(...)
(合并索引)

将以上各步还原为NUTCH命令脚本你就会发现,其实它和爬行整个网络所进行的操作是一码事。

- (start logger, etc)
- bin/nutch admin db -create
- bin/nutch inject db ...
- (for 1 to depth:)
   - bin/nutch generate ...
   - bin/nutch fetch ...
   - bin/nutch updatedb ...
- (call net.nutch.FileUtil.fullyDelete(...))
- bin/nutch generate ...
- bin/nutch index ...
- bin/nutch dedup ...
- bin/nutch merge ...

如果我们想在自己的程序中使用爬虫功能,那么我们可以将这个类拷贝到我们自己程序中需要的地方,然后通过"bin/nutch"调用这个类的命令来爬行网络。但是,因为实际的爬行抓取功能主要是在Fetcher.main()实现的,只通过这个类我们并没有进行什么实质的自定义爬行,而只是调用了NUTCH已有的爬行功能。(未完待续
 
 
继续剖析NUTCH爬虫。接下来的几个命令和命令调用的类,主要是为最核心的fetch工作做准备的,我们首先来看看以下这些操作,然后集中精力再看fetch类。

Admin -creat 命令:net.nutch.tools.WebDBAdminTool

Admin命令的作用主要是对网页库进行管理操作。其命令格式如下:

java net.nutch.tools.WebDBAdminTool db [-create] [-textdump dumpPrefix] [-scoredump] [-top k]

其中[-creat]选项的含义就是创建网页库,它通过生成WEBDBWriter对象来完成工作,然后再关闭此对象。

 

利用spam作为文件夹执行此命令,执行后生产的网页库物理文件如下所示:

$ bin/nutch admin spam -create
$ find spam -type file | xargs ls -l
-rw-r--r-- 1 kangas users   0 Oct 25 18:31 spam/dbreadlock
-rw-r--r-- 1 kangas users   0 Oct 25 18:31 spam/dbwritelock
-rw-r--r-- 1 kangas users 16 Oct 25 18:31 spam/webdb/linksByMD5/data
-rw-r--r-- 1 kangas users 16 Oct 25 18:31 spam/webdb/linksByMD5/index
-rw-r--r-- 1 kangas users 16 Oct 25 18:31 spam/webdb/linksByURL/data
-rw-r--r-- 1 kangas users 16 Oct 25 18:31 spam/webdb/linksByURL/index
-rw-r--r-- 1 kangas users 16 Oct 25 18:31 spam/webdb/pagesByMD5/data
-rw-r--r-- 1 kangas users 16 Oct 25 18:31 spam/webdb/pagesByMD5/index
-rw-r--r-- 1 kangas users 16 Oct 25 18:31 spam/webdb/pagesByURL/data
-rw-r--r-- 1 kangas users 16 Oct 25 18:31 spam/webdb/pagesByURL/index
inject命令:net.nutch.db.WebDBInjector

此命令的主要作用就是将新的URL写入网页库,命令格式如下:

WebDBInjector <db_dir> (-urlfile <url_file> | -dmozfile <dmoz_file>) [-subset <subsetDenominator>] [-includeAdultMaterial] [-skew skew] [-noDmozDesc] [-topicFile <topic list file>] [-topic <topic> [-topic <topic> [...]]]

WebDBInjector.main() 可以接受两个选择项. "-urlfile" parses a simple list ofURLs with oneURL per line. "-dmozfile" is for parsingDMOZRDF files, which is useful for bootstrapping a whole-web database.

我们首先建立spam_url.txt文件,在文件里面写入一个url,然后运行bin/nutch inject命令。结果如下:

$ vi spam_url.txt 
$ bin/nutch inject spam -urlfile spam_url.txt
$ find spam -type file | xargs ls -l
-rw-r--r-- 1 kangas users    0 Oct 25 18:57 spam/dbreadlock
-rw-r--r-- 1 kangas users    0 Oct 25 18:57 spam/dbwritelock
-rw-r--r-- 1 kangas users   16 Oct 25 18:57 spam/webdb/linksByMD5/data
-rw-r--r-- 1 kangas users   16 Oct 25 18:57 spam/webdb/linksByMD5/index
-rw-r--r-- 1 kangas users   16 Oct 25 18:57 spam/webdb/linksByURL/data
-rw-r--r-- 1 kangas users   16 Oct 25 18:57 spam/webdb/linksByURL/index
-rw-r--r-- 1 kangas users   89 Oct 25 18:57 spam/webdb/pagesByMD5/data
-rw-r--r-- 1 kangas users   97 Oct 25 18:57 spam/webdb/pagesByMD5/index
-rw-r--r-- 1 kangas users 115 Oct 25 18:57 spam/webdb/pagesByURL/data
-rw-r--r-- 1 kangas users   58 Oct 25 18:57 spam/webdb/pagesByURL/index
-rw-r--r-- 1 kangas users   17 Oct 25 18:57 spam/webdb/stats
我们可以看到,一个新的state文件生成,并且在文件夹pagesby…中的data/index文件被修改。

 

Generate命令net.nutch.tools.FetchListTool

此命令的主要作用是为fetch命令的执行做准备,产生其所需的新segments。格式:

FetchListTool <db_dir> <segment_dir> [-refetchonly] [-anchoroptimize linkdb] [-topN N] [-cutoff cutoffscore] [-numFetchers numFetchers] [-adddays numDays]

 

FetchListTool 被用于生成一个或者多个segments。那Segmnet是什么呢?

Segment代表一个网页集合,这个集合中的网页被作为一个小的单元统一地进行抓取和索引。它里面存储的数据主要有三个类型:

·         a "fetchlist": 将要被抓取的网页的名称列表

·         the "fetcher output": 被抓取回来的网页的文件集合

·         the "index": 利用lucene为 the fetcher output 建立的索引

 

FetchListTool.main()CrawlTool.main()中被调用,调用时带了两个参数(dir + "/db", dir + "/segments"),在处理这些参数的基础上返回一个自身的实例对象flt.emitFetchList()。运行此命令,详情如下所示:

$ bin/nutch generate spam spam_segments
$ find spam -type file | xargs ls -l
-rw-r--r-- 1 kangas users    0 Oct 25 20:18 spam/dbreadlock
-rw-r--r-- 1 kangas users    0 Oct 25 20:18 spam/dbwritelock
-rw-r--r-- 1 kangas users   16 Oct 25 20:18 spam/webdb/linksByMD5/data
-rw-r--r-- 1 kangas users   16 Oct 25 20:18 spam/webdb/linksByMD5/index
-rw-r--r-- 1 kangas users   16 Oct 25 20:18 spam/webdb/linksByURL/data
-rw-r--r-- 1 kangas users   16 Oct 25 20:18 spam/webdb/linksByURL/index
-rw-r--r-- 1 kangas users   89 Oct 25 20:18 spam/webdb/pagesByMD5/data
-rw-r--r-- 1 kangas users   97 Oct 25 20:18 spam/webdb/pagesByMD5/index
-rw-r--r-- 1 kangas users 115 Oct 25 20:18 spam/webdb/pagesByURL/data
-rw-r--r-- 1 kangas users   58 Oct 25 20:18 spam/webdb/pagesByURL/index
-rw-r--r-- 1 kangas users   17 Oct 25 20:18 spam/webdb/stats
$ find spam_segments/ -type file | xargs ls -l
-rw-r--r-- 1 kangas users 113 Oct 25 20:18 spam_segments/20041026001828/fetchlist/data
-rw-r--r-- 1 kangas users   40 Oct 25 20:18 spam_segments/20041026001828/fetchlist/index

我们可以看到,网页库的文件夹(spam)没有变化,但是segment的文件夹被创建了,里面包括data和index文件。

 

差不多了,未完待续,下次详细分析fetch。

 
下面我们来研究一下fetch操作,在爬虫中,抓取是最主要的操作。

Fetch命令:net.nutch.fetcher.Fetcher

此命令的作用就是抓取网页,但是需要注意的是,抓取的单位不是单个的网页,而是同属于一个segment的网页集合。命令格式:

Fetcher [-logLevel level] [-showThreadID] [-threads n] dir

 

在进行fetch之前,我们已经生成了webdb,在其中初始化写入了URL,并且生成了segment留待写入抓取内容。我们首先看一下Fetcher类,然后运行一下看其效果。

net.nutch.fetcher.Fetcher类依靠下面几个类:

l         FetcherThread, an inner class

l         net.nutch.parse.ParserFactory

l         net.nutch.plugin.PluginRepository

l          and, of course, any "plugin" classes loaded by the PluginRepository

Fetcher类中的main()函数的功能主要是读取参数,实例化一个Fetcher对象,设置选项,然后调用run()函数。Fetcher类的构造函数很简单,它只是实例化了所有的输入输出流:

实例对象

参数

fetchList

ArrayFile.Reader

(dir, "fetchlist")

fetchWriter

ArrayFile.Writer

(dir, "fetcher", FetcherOutput.class)

contentWriter

ArrayFile.Writer

(dir, "content", Content.class)

parseTextWriter

ArrayFile.Writer

(dir, "parse_text", ParseText.class)

parseDataWriter

ArrayFile.Writer

(dir, "parse_data", ParseData.class)

Run()函数逐个的实例化抓取线程FetcherThread对象然后触发各个线程的start()函数在其共初始化threadCount个线程并等待线程结束后或者出现大的异常后此函数调用close()结束输入输出流。
FetcherThreadFetcher类的一个内部类它继承于java.lang.Thread它只有一个实体方法run()和三个静态函数handleFetch(), handleNoFetch(), and logError().

FetcherThread.run()实例化了一个新的FetchListEntry实例名叫”fle”,然后执行以下循环:

1.      如果出现错误,记录并退出循环

2.       FetchList中取得下一个URL集,如果取得结果为空,退出循环

3.       FetchListEntry解析出URL

4.       如果FetchListEntry没有被标记为”fetch”(未抓取此URL的网页),那么调用this.handleNoFetch()函数,设置status=1。然后逐步执行:

Ø         取得此URLMD5摘要

Ø         建立FetcherOutput(fle, hash, status)

Ø         建立空的ContentParseText ParseData对象

Ø         利用这些对象调用Fetcher.outputPage()函数

5.      如果标记为”fetch”(已抓取此URL的网页),调用ProtocolFactory并取得符合此URL的协议和内容对象。

6.       调用Call this.handleFetch(url, fle, content).然后逐步执行:

Ø         调用符合此内容类型的ParserFactory.getParser()

Ø         执行parser.getParse(content)

Ø         利用新建立的FetcherOutputURLMD5摘要,产生的内容对象和已解析的ParseText调用Fetcher.outputPage()函数

7.       循环100次,在log中记录

8.       扑捉各种小的异常以及记录写入log文件

 

我们可以看出,Fetcher利用Factory类来选择合适的code去处理不同的内容类型:ProtocolFactory()获取URL的协议类型, ParserFactory 根据文件类型进行合适的内容解析。

 

我们可以看出,如果我们想对nutch爬虫进行功能上的扩充,比方说增加可抓取的web资源类型,如PDF什么的,我们就可以通过对ProtocolFactoryParserFactory的扩充来进行实现。
<p>Nutch的创始人是Doug Cutting,他同时也是Lucene、Hadoop和Avro开源项目的创始人。</p><p>Nutch诞生于2002年8月,是Apache旗下的一个用Java实现的开源搜索引擎项目,自Nutch1.2版本之后,Nutch已经从搜索引擎演化为网络爬虫,接着Nutch进一步演化为两大分支版本:1.X和2.X,这两大分支最大的区别在于2.X对底层的数据存储进行了抽象以支持各种底层存储技术。</p><p>在Nutch的进化过程中,产生了Hadoop、Tika、Gora和Crawler Commons四个Java开源项目。如今这四个项目都发展迅速,极其火爆,尤其是Hadoop,其已成为大规模数据处理的事实上的标准。Tika使用多种现有的开源内容解析项目来实现从多种格式的文件中提取元数据和结构化文本,Gora支持把大数据持久化到多种存储实现,Crawler Commons是一个通用的网络爬虫组件。</p><p>大数据这个术语最早的引用可追溯到Nutch。当时,大数据用来描述为更新网络搜索索引需要同时进行批量处理或分析的大量数据集。现在,大数据的含义已经被极大地发展了,业界将大数据的特性归纳为4个“V”。Volume数据体量巨大,Variety数据类型繁多,Value价值密度低,商业价值高,Velocity处理速度快。</p><p>Hadoop是大数据的核心技术之一,而Nutch集Hadoop之大成,是Hadoop的源头。学习Hadoop,没有数据怎么办?用Nutch抓!学了Hadoop的Map Reduce以及HDFS,没有实用案例怎么办?学习NutchNutch的很多代码是用Map Reduce和HDFS写的,哪里还能找到比Nutch更好的Hadoop应用案例呢?</p>
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值