使用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 北京

该文章在以下平台同步
- HICOOL.TOP: https://www.hicool.top/article/447
- CSDN: http://blog.csdn.net/socho/article/details/78302150
- 简书: http://www.jianshu.com/p/2e2d5f00de22

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页