Nutch是一个基于Hadoop和Lucene的一个网络爬行器,用于收集网页信息。
基于Plugin机制以提高可扩展性;多协议和多线程分布式抓取;基于插件的内容分析机制;强大的抓取预处理控制;可扩展的数据处理模型(mapReduce);全文索引器和搜索引擎(Lucene or Solor),支持分布式查询;强大的API和集成配置。
Lucene Core(全文检索库)
Solr(企业搜索平台)
ElasticSearch(分布式的支持RESTFULL的实时搜索和实时分析)
Hadoop(分布式计算和分布式存储)
Tika(MIME类型检测、语言检测、元数据和文本自动提取)
Gora(对象到NOSQL的映射)
Nutch 1.6版本、redhat 6.5
2. nutch可以在http://www.apache.org/dyn/closer.cgi/nutch/中下载,也可以通过svn迁出https://svn.apache.org/repos/asf/nutch/tags/release-1.6/项目,也可以在其Subversion中下载最新版本
[root@nutch nutch2]# svn co https://svn.apache.org/repos/asf/nutch/tags/release-1.6/
3、进入release-1.6目录,手动编译nutch
[root@nutch release-1.6]# ant
注意:需要在build.xml所在目录中运行ant命令编译nutch
在Nutch1.6版本中使用ivy依赖管理工具进行依赖管理。查看ivy.xml,可发现dependencies定义了nutch对第三方框架的依赖。所以nutch的源代码比较少,源代码中未包含第三方jar包,而是使用ivy依赖管理工具在编译的时候自动到网上进行下载。
Vi bin/nutch #用此命令查看nutch脚本内容
Ant构建之后,生成runtime文件夹,在runtime下有local和deploy两个子文件夹,分别代表nutch的两种运行方式。
Deploy:使用hadoop的方式运行,数据存储在hdfs文件系统中
loca:使用本地文件系统来运行
数据的存储位置不同
local模式中对hadoop没有依赖
deploy运行方式必须将数据存储到hadoop,对hadoop依赖
在nutch1.2之前,nutch的所有数据都是存储在hdfs中。它所有运算都是通过mapreduce编程模型来实现的,所以nutch的底层是hadoop。
[root@nutch local]# vi bin/nutch
通过查看bin/nutch脚本可以发现,在deploy模式下nutch是依赖于hadoop平台的。
通过nutch脚本,hadoop命令把apache-nutch-1.6.job提交给hadoop的JobTracker。
4. 在其example目录下有一个bin/nutch脚本用来启动nutch,也可以用来看help帮助信息
[root@nutch local]# bin/nutch
crawl:对intranet进行一站式的爬取
很多时候我们需要根据自己的情况重写crawl类,或者使用脚本的方式,对需要执行的命令自定义。
[root@nutch local]# bin/nutch crawl
Usage: Crawl <urlDir> -solr <solrURL> [-dir d] [-threads n] [-depth i] [-topN N]
初学时不知道每一个命令选项用于干嘛?这种情况下我们可以通过研读源代码的方式查看相应选项参数。
[root@nutch local]# mkdir urls
[root@nutch urls]# vi url
此参数可选,可加可不加
Nutch把网页爬取下来后,将爬取网页交给solr进行索引,之后用户通过solr来进行内容的搜索,Nutch本身并不做索引方面的工作,它只是把文档提交给solr,solr负责索引。
从这些可以看出,Nutch目前是一个网络爬虫,而不是一个搜索引擎。它的目标已经从搜索引擎蜕变为网络爬虫。
爬取的页面保存地址
因为现在是本地模式,在本地模式下只有一个map和一个reduce。在一个map和一个reduce的情况下,map/reduce的工作是串行的。
没办法充分利用cpu的多线程特性。虽然map/reduce不能并行,但是在网页抓取的过程中,即fetch阶段是可以使用多线程的。
抓取深度
写一个urls文件用于生成crawlDB数据库;以urls/crawl.txt进行配置;修改conf/nutch-site.xml,加入<property><name>http.agent.name</name><value>test-nutch</value></property>信息;另外配置JAVA_HOME环境变量,一般在/usr/lib/jvm下会装有java的环境。
[root@nutch local]#nohup bin/nutch crawl urls -dir data -threads 3 -depth 3 &
打开bin/nutch脚本,查找相关命令。如查找fetch命令所对应的类
[root@nutch local]# vi bin/nutch
按“/fetch”回车,再按“n”查找相匹配的下一条记录。
Nutch入门重点在于分析nutch脚本文件
首先理解nutch的三个数据目录:
1.crawdb,linkdb 是web link目录,存放url 及url的互联关系,作为爬行与重新爬行的依据,页面默认30天过期。
2.segments 是主目录,存放抓回来的网页。页面内容有bytes[]的raw content 和 parsed text的形式。nutch以广度优先的原则来爬行,因此每爬完一轮会生成一个segment目录。
3.index 是lucene的索引目录,是indexs里所有index合并后的完整索引,注意索引文件只对页面内容进行索引,没有进行存储,因此查询时要去访问segments目录才能获得页面内容。
资料来源 http://adt.haotui.com/thread-278-1-1.html
1. 我用了如下命令,其中dir为指定抓取目录,depth为抓取深度,输出日志如下:
lemo@lemo-laptop:~/Workspace/java/Apache/Nutch/nutch-1.2$ bin/nutch crawl urls -dir crawl.test -depth 1
crawl started in: crawl.test <--- 抓取目录,抓取后有如下目录crawldb,index,indexes,linkdb, segments
rootUrlDir = urls <--- 初始化urls目录
threads = 10 <--- 抓取线程数
depth = 1 <--- 抓取深度
indexer=lucene <--- 索引器名字
<<<<<<<<<<<<<<<<<<< Injector开始,把urls目录合并到crawl db中去
Injector: starting at 2010-11-07 19:52:45
Injector: crawlDb: crawl.test/crawldb <--- inject的输出目录
Injector: urlDir: urls <--- 输入目录
Injector: Converting injected urls to crawl db entries. <--- 这里是对urls数据进行数据模型的转换
Injector: Merging injected urls into crawl db. <--- 这里利用MP计算模型来进行Inject操作
Injector: finished at 2010-11-07 19:52:48, elapsed: 00:00:03
<<<<<<<<<<<<<<<<<<< Generate开始,产生适合抓取的urls
Generator: starting at 2010-11-07 19:52:48
Generator: Selecting best-scoring urls due for fetch. <--- 对urls进行分数计算,产生topN个进行抓取
Generator: filtering: true <--- 进行相应的urls过滤,这个在conf/regex-urlfilter.txt有配置
Generator: normalizing: true <--- 是否对urls进行规范化,这个在conf/regex-normalize.txt中配置
Generator: jobtracker is 'local', generating exactly one partition. <--- 没有使用MP,只是本地读取
Generator: Partitioning selected urls for politeness. <---
Generator: segment: crawl.test/segments/20101107195251
Generator: finished at 2010-11-07 19:52:52, elapsed: 00:00:03
<<<<<<<<<<<<<<<<<<< Fetcher开始,进行Generator产生出来的urls进行抓取
Fetcher: Your 'http.agent.name' value should be listed first in 'http.robots.agents' property.
Fetcher: starting at 2010-11-07 19:52:52
Fetcher: segment: crawl.test/segments/20101107195251 <--- 抓取数据存放目录
Fetcher: threads: 10 <--- 抓取线程数,nutch是用了一个改进的work-crew的线程模型来进行网页抓取
QueueFeeder finished: total 1 records + hit by time limit :0
fetching http://www.baidu.com/ <--- 正在抓取的url
-finishing thread FetcherThread, activeThreads=8 <--- 每个线程结束抓取提示
-finishing thread FetcherThread, activeThreads=7
-finishing thread FetcherThread, activeThreads=6
-finishing thread FetcherThread, activeThreads=5
-finishing thread FetcherThread, activeThreads=4
-finishing thread FetcherThread, activeThreads=3
-finishing thread FetcherThread, activeThreads=2
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=0
-activeThreads=0, spinWaiting=0, fetchQueues.totalSize=0 <--- 所有线程的一个状态和抓取队列状态
-activeThreads=0
Fetcher: finished at 2010-11-07 19:52:54, elapsed: 00:00:02
<<<<<<<<<<<< dbupdate开始,把新生产的outlink等数据更新来原的crawldb数据库
CrawlDb update: starting at 2010-11-07 19:52:55
CrawlDb update: db: crawl.test/crawldb
CrawlDb update: segments: [crawl.test/segments/20101107195251]
CrawlDb update: additions allowed: true
CrawlDb update: URL normalizing: true
CrawlDb update: URL filtering: true
CrawlDb update: Merging segment data into db.
CrawlDb update: finished at 2010-11-07 19:52:56, elapsed: 00:00:01
<<<<<<<<<<<<< 更新linkDb数据库
LinkDb: starting at 2010-11-07 19:52:56
LinkDb: linkdb: crawl.test/linkdb
LinkDb: URL normalize: true
LinkDb: URL filter: true
LinkDb: adding segment: file:/home/lemo/Workspace/java/Apache/Nutch/nutch-1.2/crawl.test/segments/20101107195251
LinkDb: finished at 2010-11-07 19:52:58, elapsed: 00:00:01
<<<<<<<<<<<<< index开始,对抓取数据进行索引
Indexer: starting at 2010-11-07 19:52:58
Indexer: finished at 2010-11-07 19:53:01, elapsed: 00:00:03
<<<<<<<<<<<<< 去重复数据
Dedup: starting at 2010-11-07 19:53:01
Dedup: adding indexes in: crawl.test/indexes
Dedup: finished at 2010-11-07 19:53:06, elapsed: 00:00:04
<<<<<<<<<<<<< 把新的索引与老的索引进行合并
IndexMerger: starting at 2010-11-07 19:53:06
IndexMerger: merging indexes to: crawl.test/index
Adding file:/home/lemo/Workspace/java/Apache/Nutch/nutch-1.2/crawl.test/indexes/part-00000
IndexMerger: finished at 2010-11-07 19:53:06, elapsed: 00:00:00
crawl finished: crawl.test
从上面的日志输出,
我们可以看出Nutch的抓取流程:inject->Generate->Fetch->Parse->UpdateCrawlDB->UpdateLinkDB->index shards,
而数据流模型为:inject: urls->CrawlDB;
generate: CrawlDB->segment(crawl_generate),对于哪些urls要进行generate呢?这里使用了静态和动态产生机制,静态的是那些带宽优先的、超过抓取时间的、高优先级的(PageRank)、新加入的。Fetchlist的产生一般会以topN的方式来产生,选择最优的后选者,这方面也有学者用遗传算法来实现,优先级由不同的因素来决定,一般是通过插件来实现的。动态的是那些自动检查网页更新频率和时间变化来决定网页的generate的优先级。
fetch: crawl_generate->crawl_fetch+content
crawldbupdate: parse_data->crawldb,把分析出的外链接更新到crawldb中,用于下一轮抓取
linkdb: parse_data->linkdb,把提供出的锚文本、反向链接等信息放入linkdb中
indexer: CrawlDB,LinkDB,Segment->indexes,对抓取的数据进行全文索引
Dedup: Segment->Segment,对网页进行去重,这里使用是的网页指纹的方法,对重复网页加删除标记
IndexMerger:indexes->index,把新的索引合并到旧的索引中去
1. CrawlDB,用于存储所有的urls信息,包括抓取机制,抓取状态,网页指纹和元数据。
2. LinkDB,存储每一个url的连入锚链接和锚文本
3. Segment,原始的网页内容;解析后的网页;元数据;外链接;用于索引的元文本
资料来源于http://blog.csdn.net/amuseme_lu/article/details/5993916
爬行过程在Introduction to Nutch, Part 1 Crawling 里已有详细说明,或许直接看Crawl类来理解爬行的过程。
资料来源 http://adt.haotui.com/thread-278-1-1.html
Nutch 的配置文件几乎覆盖了Nutch 所有的功能。
资料来源http://adt.haotui.com/thread-278-1-1.html
资料来源http://adt.haotui.com/thread-278-1-1.html