Nutch是基于Lucene實(shí)現(xiàn)的搜索引擎。包括全文搜索和Web爬蟲。Lucene為Nutch提供了文本索引和搜索的API。
1.有數(shù)據(jù)源,需要為這些數(shù)據(jù)提供一個(gè)搜索頁(yè)面。最好的方式是直接從數(shù)據(jù)庫(kù)中取出數(shù)據(jù)并用Lucene API 建立索引,因?yàn)槟悴恍枰獜膭e的網(wǎng)站抓取數(shù)據(jù)。
2.沒(méi)有本地?cái)?shù)據(jù)源,或者數(shù)據(jù)源非常分散的情況下,就是需要抓別人的網(wǎng)站,則使用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
啟動(dòng)后訪問(wèn) http://localhost:8080 就可以看到web服務(wù)器正常。14339
2.部署nutch
這里nutch用1.2版本,雖然現(xiàn)在已經(jīng)很高版本了,但是1.2以上已經(jīng)沒(méi)有war包,沒(méi)法做類似百度這種頁(yè)面的搜索了,而是nutch轉(zhuǎn)而給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下,當(dāng)瀏覽器訪問(wèn) http://localhost:8080/nutch 時(shí)nutch的war包會(huì)被自動(dòng)解壓部署。可以看到我們的搜索頁(yè)面
2.爬取數(shù)據(jù)
nutch目錄下,新建文件url.txt,把我們要抓的網(wǎng)站填入,內(nèi)容
https://www.hicool.top/
有個(gè)過(guò)濾規(guī)則,我們上一步填入的網(wǎng)站,需要經(jīng)過(guò)這個(gè)規(guī)則過(guò)濾才可抓取,否則不能。修改過(guò)濾規(guī)則,查看conf/craw-urlfilter.txt文件
# accept hosts in MY.DOMAIN.NAME
+^http://([a-z0-9]*\.)*MY.DOMAIN.NAME/
這其實(shí)是一個(gè)正則表達(dá)式,把加號(hào)那一行,改為僅僅允許自己網(wǎng)站通過(guò)
+^http://([a-z0-9]*\.)*hicool.top/
這樣可以只把自己的網(wǎng)站抓下來(lái)了。修改conf/nutch-site.xml文件,在configuration標(biāo)簽內(nèi)增加如下索引目錄屬性,指定檢索器讀取數(shù)據(jù)的路徑。另外增加一個(gè)http.agent.name和一個(gè)http.robots.agents節(jié)點(diǎn),否則不能抓取。因?yàn)閚utch遵守了 robots協(xié)議,在爬行人家網(wǎng)站的時(shí)候,把自己的信息提交給被爬行的網(wǎng)站以供識(shí)別。
<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是指定搜索結(jié)果存放路徑。http.agent.name的value隨便填一個(gè),而http.robots.agents的value必須填你的的http.agent.name的值,否則報(bào)錯(cuò)"Your 'http.agent.name' value should be listed first in 'http.robots.agents' property"。
注意:默認(rèn)不開啟對(duì)https網(wǎng)站抓取的支持,如果要開啟,添加如下內(nèi)容到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>
這實(shí)際是使用了protocol-httpclient插件下載https網(wǎng)頁(yè),至于別的插件都是一些過(guò)濾解析網(wǎng)頁(yè)的。添加了插件之后,就可以爬https的網(wǎng)站了。目前已有的協(xié)議及支撐插件如下:
http:
protocol-http
protocol-httpclient
https:
protocol-httpclient
ftp:
protocol-ftp
file:
protocol-file
Nutch 的爬蟲有兩種方式
? 爬行企業(yè)內(nèi)部網(wǎng)(Intranet crawling)。針對(duì)少數(shù)網(wǎng)站進(jìn)行,用 crawl 命令。
? 爬行整個(gè)互聯(lián)網(wǎng)。 使用低層的 inject, generate, fetch 和 updatedb 命令,具有更強(qiáng)的可控制性。
我們使用crawl命令,抓數(shù)據(jù)
[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
上面的過(guò)程太長(zhǎng),我略過(guò)了很多。參數(shù)含義說(shuō)明如下:
-dir 指定存放爬行結(jié)果的目錄,本次抓取結(jié)果數(shù)據(jù)存放到sports目錄中;
-depth 表明需要抓取的頁(yè)面深度,本次抓取深度為10層;
-topN 表明只抓取前N個(gè)url,本次抓取為取每一層的前100個(gè)頁(yè)面;
-threads 指定Crawl采取下載的線程數(shù),我用這個(gè)一直抓不到數(shù)據(jù),就把它去掉了。
根據(jù)下載過(guò)程可以看出nutch爬取網(wǎng)頁(yè)并建立索引庫(kù)的過(guò)程如下:
1)插入器(Injector)向網(wǎng)頁(yè)數(shù)據(jù)庫(kù)添加起始根URL;
2)按照要求抓取的層數(shù),用生成器(Generator)生成待下載任務(wù);
3)調(diào)用獲取器(Fetcher),按照指定線程數(shù)實(shí)際下載相應(yīng)頁(yè)面;
4)調(diào)用頁(yè)面分析器(ParseSegment),分析下載內(nèi)容;
5)調(diào)用網(wǎng)頁(yè)數(shù)據(jù)庫(kù)管理工具(CrawlDb),把二級(jí)鏈接添加到庫(kù)中等待下載;
6)調(diào)用鏈接分析工具(LinkDb),建立反向鏈接;
7)調(diào)用索引器(Indexer),利用網(wǎng)頁(yè)數(shù)據(jù)庫(kù)、鏈接數(shù)據(jù)庫(kù)和具體下載的頁(yè)面內(nèi)容,創(chuàng)建當(dāng)前數(shù)據(jù)索引;
8)調(diào)用重復(fù)數(shù)據(jù)刪除器(DeleteDuplicates),刪除重復(fù)數(shù)據(jù);
9)調(diào)用索引合并器(IndexMerger),把數(shù)據(jù)合并到歷史索引庫(kù)中。
本地測(cè)試下搜索結(jié)果,搜關(guān)鍵字“1”
[root@localhost nutch]# bin/nutch org.apache.nutch.searcher.NutchBean 1
Total hits: 193
0 20171019203949/https://www.hicool.top/
... Liberalman 的主頁(yè) ...
......
......
搜到了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個(gè)頁(yè)面。
3.在web頁(yè)面展示搜索結(jié)果
修改/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>
把我們上一步抓取數(shù)據(jù)的存放路徑配置到tomcat下,重啟tomcat,就可以在瀏覽器中搜索了。
4.篩選鏈接
有些鏈接我們需要抓取,有些我們則需要排除掉。怎樣才能有一個(gè)篩選機(jī)制,過(guò)濾掉冗余的鏈接呢?
編輯conf/regex-urlfilter.txt
# skip file: ftp: and mailto: urls
#過(guò)濾掉file:ftp等不是html協(xié)議的鏈接
-^(file|ftp|mailto):
# skip image and other suffixes we can't yet parse
#過(guò)濾掉圖片等格式的鏈接
-\.(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.
-[?*!@=] 過(guò)濾掉汗特殊字符的鏈接,因?yàn)橐廊「嗟逆溄樱热绾?的鏈接
# skip URLs with slash-delimited segment that repeats 3+ times, to break loops
#過(guò)濾掉一些特殊格式的鏈接
-.*(/[^/]+)/[^/]+\1/[^/]+\1/
# accept anything else
#接受所有的鏈接,這里可以修改為只接受自己規(guī)定類型的鏈接
+.
我現(xiàn)在只想抓取 https://www.hicool.top/article/324 類似這樣的,只把 /article/*
下的內(nèi)容抓出來(lái)的需求。修改如下
# accept anything else
+^https:\/\/www\.hicool\.top\/article\/.*$
如果有哪些路徑我想排除掉,不抓取
-^https:\/\/www\.hicool\.top\/category/.*$
+^https:\/\/www\.hicool\.top\/article\/.*$
這樣/category/頁(yè)面下的都排除了。這些正則表達(dá)式列表,只要有一個(gè)滿足條件filter()方法就返回結(jié)果。
抓取動(dòng)態(tài)內(nèi)容
我們平常訪問(wèn)網(wǎng)站的時(shí)候,往往有"?"以及后面帶參數(shù),這種動(dòng)態(tài)的內(nèi)容默認(rèn)也不抓取,需要配置。
在conf下面的2個(gè)文件:regex-urlfilter.txt,crawl-urlfilter.txt
# skip URLs containing certain characters as probable queries, etc.
-[?*!@=] (-改+)
這段意思是跳過(guò)在連接中存在? * ! @ = 的頁(yè)面,因?yàn)槟J(rèn)是跳過(guò)所以,在動(dòng)態(tài)頁(yè)中存在?一般按照默認(rèn)的是不能抓取到的。可以在上面2個(gè)文件中都注釋掉:
# -[?*!@=]
另外增加允許的一行
# accept URLs containing certain characters as probable queries, etc.
+[?=&]
意思是抓取時(shí)候允許抓取連接中帶 ? = & 這三個(gè)符號(hào)的連接
注意:兩個(gè)文件都需要修改,因?yàn)镹UTCH加載規(guī)則的順序是crawl-urlfilter.txt-> regex-urlfilter.txt
5.按詞劃分和中文分詞
看看上文最后的效果,你會(huì)發(fā)現(xiàn),搜索是按單個(gè)字來(lái)區(qū)分的,你輸入一句話,每個(gè)字都被單獨(dú)搜了一遍,導(dǎo)致不想關(guān)的信息太冗余。原來(lái),nutch默認(rèn)對(duì)中文按字劃分,而不是按詞劃分。
so,我們要達(dá)到按詞劃分以減少冗余的目的,則:
1.修改源代碼。直接對(duì)Nutch分詞處理類進(jìn)行修改,調(diào)用已寫好的一些分詞組件進(jìn)行分詞。
2.使用分詞插件。按照Nutch的插件編寫規(guī)則重新編寫或者添加中文分詞插件。
這里我使用修改源碼方式,得下載源碼重新編譯了。關(guān)于 IKAnalyzer3.2.8.jar 這個(gè)包,我是在網(wǎng)上搜到下載的。可以看這篇 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>)+ >
,后面那個(gè)"+"號(hào)是多次,就組成詞了。
Lucene中使用JavaCC這個(gè)Java語(yǔ)言分析器按照規(guī)則自動(dòng)生成的源代碼。確保安裝了該工具。
[root@localhost nutch]# cd src/java/org/apache/nutch/analysis/
[root@localhost analysis]# javacc NutchAnalysis.jj
當(dāng)前路徑新生成的源碼會(huì)覆蓋掉舊的
修改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 }
這份代碼原來(lái)是沒(méi)有ParseException這個(gè)異常處理的,給它IOException的后面加上",ParseException",這是我修改過(guò)后的。
修改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 }
我把原來(lái)的代碼注釋了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
編譯成功,產(chǎn)生一個(gè)build目錄
[root@localhost nutch]# cp build/nutch-1.2.job ./
再生產(chǎn)war包
[root@localhost nutch]# ant war
[root@localhost nutch]# cp build/nutch-1.2.jar ./
[root@localhost nutch]# cp build/nutch-1.2.war ./
我們的編譯就大功告成了。剩下的就是重復(fù)跟上文部署一個(gè)搜索引擎的步驟,過(guò)程略。有一點(diǎn)需要說(shuō)明,新的搜索界面,輸入關(guān)鍵詞進(jìn)行搜索,這時(shí)會(huì)出現(xiàn)空白頁(yè)。還需要修改 /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,需要注意。重啟后的分詞效果
可以看到已經(jīng)以“設(shè)計(jì)模式”、“設(shè)計(jì)”、“模式”這些詞看分關(guān)鍵詞搜索了,OK,成功!
問(wèn)題
每次重新爬后,要重啟tomcat才能順利訪問(wèn)
1. Stopping at depth=0 - no more URLs to fetch
特么的,網(wǎng)上看一堆類似這么寫的
bin/nutch crawl url.txt -dir crawl -depth 10 -topN 100 -treads 10
我照抄,結(jié)果一直報(bào)錯(cuò)Stopping at depth=0 - no more URLs to fetch.害得我搜便各種各樣的辦法,改來(lái)改去,都無(wú)濟(jì)于事,過(guò)濾那個(gè)地方的正則表達(dá)式我都到別的地方去驗(yàn)證了,沒(méi)問(wèn)題。0.9和1.2版本換了n次,配置了一堆東西,最后自己發(fā)現(xiàn), -treads 10 這個(gè)參數(shù)有大問(wèn)題,帶上它怎么都失敗,去掉立刻OK了
。
2. 中文亂碼問(wèn)題
配置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
參考
創(chuàng)建于 2017-10-19 北京,更新于 2017-10-23 北京
該文章在以下平臺(tái)同步