美文网首页
使用nutch搭建类似百度/谷歌的搜索引擎

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

作者: Liberalman | 来源:发表于2017-10-21 21:40 被阅读705次

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

    该文章在以下平台同步

    相关文章

      网友评论

          本文标题:使用nutch搭建类似百度/谷歌的搜索引擎

          本文链接:https://www.haomeiwen.com/subject/sgewuxtx.html