使用nutch搭建类似百度/谷歌的搜索引擎
Posted Liberal-man
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用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
以上是关于使用nutch搭建类似百度/谷歌的搜索引擎的主要内容,如果未能解决你的问题,请参考以下文章
Mac自己搭建爬虫搜索引擎(nutch+elasticsearch是失败的尝试,改用scrapy+elasticsearch)