使用nutch搭建类似百度/谷歌的搜索引擎

Nutch是基于Lucene实现的搜索引擎。包括全文搜索和Web爬虫。Lucene为Nutch提供了文本索引和搜索的API。

1.有数据源,需要为这些数据提供一个搜索页面。最好的方式是直接从数据库中取出数据并用Lucene API 建立索引,因为你不需要从别的网站抓取数据。
2.没有本地数据源,或者数据源非常分散的情况下,就是需要抓别人的网站,则使用Nutch。

1.安装

1.安装tomcat

[root@localhost ~]# wget https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.1/bin/apache-tomcat-9.0.1.tar.gz
[root@localhost ~]# tar xvzf apache-tomcat-9.0.1.tar.gz -C /usr/local/
[root@localhost ~]# cd /usr/local/
[root@localhost local]# mv apache-tomcat-9.0.1/ tomcat
[root@localhost local]# /usr/local/tomcat/bin/startup.sh

启动后访问 http://localhost:8080 就可以看到web服务器正常。14339

2.部署nutch
这里nutch用1.2版本,虽然现在已经很高版本了,但是1.2以上已经没有war包,没法做类似百度这种页面的搜索了,而是nutch转而给solr提供搜索支持。

[root@localhost ~]# wget http://archive.apache.org/dist/nutch/apache-nutch-1.2-bin.tar.gz
[root@localhost ~]# tar xvf apache-nutch-1.2-bin.tar.gz -C /usr/local/
[root@localhost ~]# cd /usr/local/nutch-1.2/
[root@localhost local]# mv nutch-1.2/ nutch
[root@localhost local]# cd nutch/
[root@localhost nutch]# cp nutch-1.2.war /usr/local/tomcat/webapps/nutch.war

apache下,当浏览器访问 http://localhost:8080/nutch 时nutch的war包会被自动解压部署。可以看到我们的搜索页面

2.爬取数据

nutch目录下,新建文件url.txt,把我们要抓的网站填入,内容

https://www.hicool.top/

有个过滤规则,我们上一步填入的网站,需要经过这个规则过滤才可抓取,否则不能。修改过滤规则,查看conf/craw-urlfilter.txt文件

# accept hosts in MY.DOMAIN.NAME
+^http://([a-z0-9]*\.)*MY.DOMAIN.NAME/

这其实是一个正则表达式,把加号那一行,改为仅仅允许自己网站通过

+^http://([a-z0-9]*\.)*hicool.top/

这样可以只把自己的网站抓下来了。修改conf/nutch-site.xml文件,在configuration标签内增加如下索引目录属性,指定检索器读取数据的路径。另外增加一个http.agent.name和一个http.robots.agents节点,否则不能抓取。因为nutch遵守了 robots协议,在爬行人家网站的时候,把自己的信息提交给被爬行的网站以供识别。

<property>
    <name>http.agent.name</name>
    <value>hicool.top</value>
    <description>Hello,welcom to visit www.hicool.top</description>
</property>
<property>
    <name>http.robots.agents</name>
    <value>hicool.top,*</value>
</property>
<property>
    <name>searcher.dir</name>
    <value>/usr/local/nutch/crawl</value>
    <description></description>
</property>

searcher.dir是指定搜索结果存放路径。http.agent.name的value随便填一个,而http.robots.agents的value必须填你的的http.agent.name的值,否则报错"Your 'http.agent.name' value should be listed first in 'http.robots.agents' property"。

注意:默认不开启对https网站抓取的支持,如果要开启,添加如下内容到nutch-site.xml

<property>
  <name>plugin.includes</name>
  <value>protocol-httpclient|urlfilter-regex|parse-(html|tika)|index-(basic|anchor)|indexer-solr|scoring-opic|urlnormalizer-(pass|regex|basic)|parse-jsoup</value>
</property>

这实际是使用了protocol-httpclient插件下载https网页,至于别的插件都是一些过滤解析网页的。添加了插件之后,就可以爬https的网站了。目前已有的协议及支撑插件如下:

http:
    protocol-http
    protocol-httpclient
https:
    protocol-httpclient
ftp:
    protocol-ftp
file:
    protocol-file

Nutch 的爬虫有两种方式
• 爬行企业内部网(Intranet crawling)。针对少数网站进行,用 crawl 命令。
• 爬行整个互联网。 使用低层的 inject, generate, fetch 和 updatedb 命令,具有更强的可控制性。

我们使用crawl命令,抓数据

[root@localhost nutch]# bin/nutch crawl url.txt -dir crawl -depth 10 -topN 100
crawl started in: crawl
rootUrlDir = url.txt
threads = 10
......
......
......
IndexMerger: merging indexes to: crawl/index
Adding file:/usr/local/nutch/crawl/indexes/part-00000
IndexMerger: finished at 2017-10-19 19:59:50, elapsed: 00:00:01
crawl finished: crawl

上面的过程太长,我略过了很多。参数含义说明如下:
-dir 指定存放爬行结果的目录,本次抓取结果数据存放到sports目录中;
-depth 表明需要抓取的页面深度,本次抓取深度为10层;
-topN 表明只抓取前N个url,本次抓取为取每一层的前100个页面;
-threads 指定Crawl采取下载的线程数,我用这个一直抓不到数据,就把它去掉了。

根据下载过程可以看出nutch爬取网页并建立索引库的过程如下:
1)插入器(Injector)向网页数据库添加起始根URL;
2)按照要求抓取的层数,用生成器(Generator)生成待下载任务;
3)调用获取器(Fetcher),按照指定线程数实际下载相应页面;
4)调用页面分析器(ParseSegment),分析下载内容;
5)调用网页数据库管理工具(CrawlDb),把二级链接添加到库中等待下载;
6)调用链接分析工具(LinkDb),建立反向链接;
7)调用索引器(Indexer),利用网页数据库、链接数据库和具体下载的页面内容,创建当前数据索引;
8)调用重复数据删除器(DeleteDuplicates),删除重复数据;
9)调用索引合并器(IndexMerger),把数据合并到历史索引库中。

本地测试下搜索结果,搜关键字“1”

[root@localhost nutch]# bin/nutch org.apache.nutch.searcher.NutchBean 1
Total hits: 193
 0 20171019203949/https://www.hicool.top/
 ... Liberalman 的主页 ...
 ......
 ......

搜到了193条信息。剩下的我都省略显示了。

使用Readdb工具摘要描述

[root@localhost nutch]# bin/nutch readdb crawl/crawldb/ -stats
CrawlDb statistics start: crawl/crawldb/
Statistics for CrawlDb: crawl/crawldb/
TOTAL urls:     296
retry 0:        286
retry 1:        10
min score:      0.0
avg score:      0.009496622
max score:      1.11
status 1 (db_unfetched):        18
status 2 (db_fetched):  275
status 4 (db_redir_temp):       3
CrawlDb statistics: done

爬到了296个页面。

3.在web页面展示搜索结果

修改/usr/local/tomcat/webapps/nutch/WEB-INF/classes/nutch-site.xml

<property>
    <name>http.agent.name</name>
    <value>hicool.top</value>
    <description>Hello,welcom to visit www.hicool.top</description>
</property>
<property>
    <name>http.robots.agents</name>
    <value>hicool.top,*</value>
</property>
<property>
    <name>searcher.dir</name>
    <value>/usr/local/nutch/crawl</value>
    <description></description>
</property>

把我们上一步抓取数据的存放路径配置到tomcat下,重启tomcat,就可以在浏览器中搜索了。


4.筛选链接

有些链接我们需要抓取,有些我们则需要排除掉。怎样才能有一个筛选机制,过滤掉冗余的链接呢?

编辑conf/regex-urlfilter.txt

# skip file: ftp: and mailto: urls
#过滤掉file:ftp等不是html协议的链接
-^(file|ftp|mailto):

# skip image and other suffixes we can't yet parse
#过滤掉图片等格式的链接
-\.(gif|GIF|jpg|JPG|png|PNG|ico|ICO|css|sit|eps|wmf|zip|ppt|mpg|xls|gz|rpm|tgz|mov|MOV|exe|jpeg|JPEG|bmp|BMP)$

# skip URLs containing certain characters as probable queries, etc.
-[?*!@=] 过滤掉汗特殊字符的链接,因为要爬取更多的链接,比如含?=的链接

# skip URLs with slash-delimited segment that repeats 3+ times, to break loops
#过滤掉一些特殊格式的链接
-.*(/[^/]+)/[^/]+\1/[^/]+\1/

# accept anything else
#接受所有的链接,这里可以修改为只接受自己规定类型的链接
+.

我现在只想抓取 https://www.hicool.top/article/324 类似这样的,只把 /article/* 下的内容抓出来的需求。修改如下

# accept anything else
+^https:\/\/www\.hicool\.top\/article\/.*$

如果有哪些路径我想排除掉,不抓取

-^https:\/\/www\.hicool\.top\/category/.*$
+^https:\/\/www\.hicool\.top\/article\/.*$

这样/category/页面下的都排除了。这些正则表达式列表,只要有一个满足条件filter()方法就返回结果。

抓取动态内容

我们平常访问网站的时候,往往有"?"以及后面带参数,这种动态的内容默认也不抓取,需要配置。

在conf下面的2个文件:regex-urlfilter.txt,crawl-urlfilter.txt

# skip URLs containing certain characters as probable queries, etc.
-[?*!@=] (-改+)

这段意思是跳过在连接中存在? * ! @ = 的页面,因为默认是跳过所以,在动态页中存在?一般按照默认的是不能抓取到的。可以在上面2个文件中都注释掉:

# -[?*!@=]

另外增加允许的一行

# accept URLs containing certain characters as probable queries, etc.
+[?=&]

意思是抓取时候允许抓取连接中带 ? = & 这三个符号的连接
注意:两个文件都需要修改,因为NUTCH加载规则的顺序是crawl-urlfilter.txt-> regex-urlfilter.txt

5.按词划分和中文分词

看看上文最后的效果,你会发现,搜索是按单个字来区分的,你输入一句话,每个字都被单独搜了一遍,导致不想关的信息太冗余。原来,nutch默认对中文按字划分,而不是按词划分。
so,我们要达到按词划分以减少冗余的目的,则:
1.修改源代码。直接对Nutch分词处理类进行修改,调用已写好的一些分词组件进行分词。
2.使用分词插件。按照Nutch的插件编写规则重新编写或者添加中文分词插件。

这里我使用修改源码方式,得下载源码重新编译了。关于 IKAnalyzer3.2.8.jar 这个包,我是在网上搜到下载的。可以看这篇 https://github.com/wks/ik-analyzer 安装此包。

[root@localhost ~]# wget http://archive.apache.org/dist/nutch/apache-nutch-1.2-src.tar.gz
[root@localhost ~]# tar xvf apache-nutch-1.2-src.tar.gz -C /usr/local/
[root@localhost ~]# cd /usr/local/
[root@localhost local]# mv apache-nutch-1.2/ nutch
[root@localhost local]# cd nutch
[root@localhost nutch]# mv ~/IKAnalyzer3.2.8.jar lib/

编辑源码生成文件 src/java/org/apache/nutch/analysis/NutchAnalysis.jj

130   // chinese, japanese and korean characters
131 | <SIGRAM: <CJK> >

这是按字划分,改为 | <SIGRAM: (<CJK>)+ >,后面那个"+"号是多次,就组成词了。

Lucene中使用JavaCC这个Java语言分析器按照规则自动生成的源代码。确保安装了该工具。

[root@localhost nutch]# cd src/java/org/apache/nutch/analysis/
[root@localhost analysis]# javacc NutchAnalysis.jj

当前路径新生成的源码会覆盖掉旧的

修改NutchAnalysis.java

 49   /** Construct a query parser for the text in a reader. */
 50   public static Query parseQuery(String queryString, Configuration conf) throws IOException,ParseException {
 51     return parseQuery(queryString, null, conf);
 52   }
 53 
 54   /** Construct a query parser for the text in a reader. */
 55   public static Query parseQuery(String queryString, Analyzer analyzer, Configuration conf)
 56     throws IOException,ParseException {
 57     NutchAnalysis parser = new NutchAnalysis(
 58           queryString, (analyzer != null) ? analyzer : new NutchDocumentAnalyzer(conf));
 59     parser.queryString = queryString;
 60     parser.queryFilters = new QueryFilters(conf);
 61     return parser.parse(conf);
 62   }

这份代码原来是没有ParseException这个异常处理的,给它IOException的后面加上",ParseException",这是我修改过后的。

修改NutchDocumentAnalyzer.java

103   /** Returns a new token stream for text from the named field. */
104   public TokenStream tokenStream(String fieldName, Reader reader) {
105     /*Analyzer analyzer;
106     if ("anchor".equals(fieldName))
107       analyzer = ANCHOR_ANALYZER;
108     else
109       analyzer = CONTENT_ANALYZER;*/
110     Analyzer analyzer = new org.wltea.analyzer.lucene.IKAnalyzer();
111 
112     return analyzer.tokenStream(fieldName, reader);
113   }

我把原来的代码注释了return之前哪一行是新加的。

回到根目录,修改build.xml,在 <target name="war" depends="jar,compile,generate-docs"></target><lib></lib>之间加入IKAnalyzer3.2.8.jar,使得编译可以依赖上。

200         <include name="log4j-*.jar"/>
201         <include name="IKAnalyzer3.2.8.jar"/>
202       </lib>

开始编译

[root@localhost nutch]# ant

编译成功,产生一个build目录

[root@localhost nutch]# cp build/nutch-1.2.job ./

再生产war包

[root@localhost nutch]# ant war
[root@localhost nutch]# cp build/nutch-1.2.jar ./
[root@localhost nutch]# cp build/nutch-1.2.war ./

我们的编译就大功告成了。剩下的就是重复跟上文部署一个搜索引擎的步骤,过程略。有一点需要说明,新的搜索界面,输入关键词进行搜索,这时会出现空白页。还需要修改 /usr/local/tomcat/webapps/nutch-1.2/WEB-INF/classes/nutch-site.xml 文件,添加加载插件的属性:

<property>
  <name>plugin.includes</name>
  <value>protocol-http|urlfilter-regex|parse-(text|html|js)|analysis-(zh)|index-basic|query-(basic|site|url)|summary-lucene|scoring-opic|urlnormalizer-(pass|regex|basic)</value>
</property>

这里使用protocol-http而不是protocol-httpclient,需要注意。重启后的分词效果



可以看到已经以“设计模式”、“设计”、“模式”这些词看分关键词搜索了,OK,成功!

问题

每次重新爬后,要重启tomcat才能顺利访问

1. Stopping at depth=0 - no more URLs to fetch

特么的,网上看一堆类似这么写的

bin/nutch crawl url.txt -dir crawl -depth 10 -topN 100 -treads 10

我照抄,结果一直报错Stopping at depth=0 - no more URLs to fetch.害得我搜便各种各样的办法,改来改去,都无济于事,过滤那个地方的正则表达式我都到别的地方去验证了,没问题。0.9和1.2版本换了n次,配置了一堆东西,最后自己发现, -treads 10 这个参数有大问题,带上它怎么都失败,去掉立刻OK了

2. 中文乱码问题

配置tomcat的conf文件夹下的server.xml
修改如下

    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8" useBodyEncodingForURI="true"/>

找到这一段,添加URIEncoding="UTF-8" useBodyEncodingForURI="true"
重启一下Tomcat

参考


创建于 2017-10-19 北京,更新于 2017-10-23 北京

该文章在以下平台同步

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容