董 哲 祝福松
(北方工业大学 电气与控制工程学院,北京 100043)
当前在食品安全领域,食品安全信息的获取主要依靠百度谷歌等通用搜索引擎,无法满足人们对食品安全信息快速、精确查找的需求。随着搜索引擎技术快速发展,国内外出现了许多面向各领域的垂直搜索引擎,但能够搜索食品安全信息的引擎较少。曹奇峰在文献[1]中提出基于Nutch的食品安全信息垂直搜索引擎的研究。通过Nutch框架对相关食品安全主题网页进行爬取建立索引库,综合评分算法将索引内容进行排序,最终给出搜索结果。王亮等人在文献[2]中设计了食品安全科普网站的建立,提出了个性化的搜索引擎,通过对用户搜索日志的挖掘,发现不同搜索在时序上的关联,并利用这些关联对新的用户搜索进行扩展,给出延伸的搜索结果。搜索引擎的建立大同小异,区别在于资源库的建立,与搜索引擎的排序算法。本文采用的是基于ES构建搜索引擎架构,使用Scrapy-redis分布式爬虫构建食品安全资源库,在性能上和速度上更优。通过对此搜索引擎的建立过程,涉及对目标网站的爬取,对资源的去重清洗,以及对资源库系统的建立过程,就可以适用于其他资源库的建设中,其具有很好的通用性。
本系统被分为四个模块。分别是:爬虫模块,搜索模块,数据可视化模块,后端数据处理模块。
从特定网站中按照爬取策略爬取相关内容,并将爬取到的内容进行清洗、去重等处理,并保存到本地数据库中。
索引过程,将爬取到的资源库,保存到ES中。搜索过程,为用户提供搜索服务。
用户输入搜索内容,及显示搜索结果。
用于API解析与处理,如图1所示。
图1 系统总体架构
爬虫是根据既定的要求,有目的地筛选所有符合条件的URL进行爬取,并根据要求提取文本信息,爬虫模块的设计是在基于Scrapy-redis组件的基础上进行进行功能的扩展,主要模块包括页面爬取功能子模块,URL过滤功能子模块,文本相似过滤功能子模块。
1.1 Scrapy爬虫系统及反反爬虫策略
Scrapy主要包含引擎(Scrapy Engine)、调度器(Scheduler)、下载器(Downloader)、爬虫(Spiders)、项目管道(Item Pipeline)、下载器中间件(Downloader Middlewares)、爬虫中间件(Spider Middlewares)、调度中间件(Scheduler Middlewares)。
Engine是整个框架的“大脑”,控制爬虫的运行。Spider通过自定义设置控制Engine向调度器发送指令,调度器得到指令后处理后发送请求给下载器,下载器根据接受的请求从互联网下载相关镜像到本地,再传递给spiders,spiders对数据进行处理,之后将数据传入项目管道保存或输出,获取的URL发送到Engine进行验证处理,已爬取的URL会被丢掉,未爬取的URL排序后传递到调度器待下载队列,准备下一步抓取。只要调度器不为空,爬虫将一直运行下去[3],如图2所示。
图2 爬虫的基本流程图
为了爬取网页内容,提取相关字段,在本文中采用xpath正则表达式来匹配相关字段,选择相应DOM元素,将其下载到items中,最后保存到数据库中。在本文中,将爬取的目标选择了食品伙伴网(http://www.foodmate.net/) ,相对应字段的Xpath表达式为:
对于本次反反爬虫策略,主要采用的是设置User-Agent,通过github上开源模块fake-useragent模块来动态的改变User-Agent值从而直接更改header中的User-Agent值来达到目的。
1.2 分布式爬虫
在本文中,爬虫模块是基于Scrapy-Redis分布式爬虫主从架构构建而成,使用Redis服务器作为任务队列,将主服务器作为控制节点负责所有从服务器运行网络爬虫的主机进行管理,爬虫只需要从控制节点那里接收任务,并把新生成任务提交给控制节点,如图3所示。
图3 分布式爬虫的策略示意图
其中,主服务器主要负责URL去重和任务分配,而从服务器主要负责爬虫任务。
在进行数据爬取时,若不进行URL去重,不仅会降低爬虫的效率,还会造成储存资源的浪费。Scrapy框架默认的URL去重方法由dupefilters去重器通过RFPDupeFilter 类实现,RFPDupeFilter类会对每一个请求生成信息指纹fp,但是这种URL去重方法比较耗费内存,而本文采用的是通过Bloom Filter算法的布隆过滤器就可以很好的改进这个问题。
Scrapy-redis默认的去重模块RFPDupeFilter主要通过fp(指纹)标准过滤,去重结构使用的是redis中的集合(set)实现去重功能。在计算机中通过链表的数据结构来储存集合,而redis是内存数据库,也就意味着所有爬取的请求、数据,去重集合都会存在内存中,请求队列会随着爬取的进行。动态出入,不会无限叠加,爬取到的数据一般会转移到其他数据库,也不会无限叠加,但去重集合会随着爬取的进行,添加新的指纹,导致占用的内存空间不断增大,最终可能影响系统的性能。而布隆过滤器这种比较巧妙的概率型数据结构相比于传统的List、Set、Map等数据结构,更高效,占用空间更少。
该模块通过Scrapy提供的Item pipeline组件机制实现了一个对文本去重的方法类,通过编写pipeline组件里的类方法,规定它的执行顺序,实现当网络爬虫的数据items通过时,与已经入库的数据进行相似度判别,相似度较高的items将被丢弃,否则进入下一个pipeline中,直至被保存到数据库中。
在本文中,对文本相似度判别的类方法是基于SimHash算法[4],它通过调用Jieba分词,对字段内容进行分词,运用TF-IDF算法从中提取带有权重的关键词特征向量列表,然后将得到的关键词特征向量列表传给simHash类中,simHash类实现Simhash算法的全部流程(关键词特征向量→哈希→加权→累加→二值化),进而得到该文本64位二进制SimHash值,如果待测文本的SimHash值存在于语义指纹库中的,则可以直接判定重复,否则将比较待测文本与语义指纹库SimHash值的海明距离,一般海明距离小于等于3,则为相似,如 图4所示。
图4 文本去重的主要流程图
4.1 ES全文搜索
ES是一款基于Lucene的开源工具包,支持分布式的搜索引擎框架,可以实现海量数据的快速储存和搜索,提供了多种RESTful 风格的Web接口,能够解决各种用例,达到实时搜索的目的。是目前企业级应用最为常见的搜索引擎框架之一[5]。本文中,采用ES进行全文搜索主要包括两个过程:索引过程和搜索过程,如图5所示。
图5 食品安全搜索整体架构图
由系统的总体整体架构可以看出,食品安全搜索引擎的核心是ES服务器,用于食品安全相关信息的存储,同时返回基于RESTful Web的数据接口,返回的数据格式为JSON形式,进而方便数据的二次处理和利用。
4.2 ES索引和搜索过程
ES在索引过程中是将爬虫爬取到的数据保存并根据映射定义的字段类型进行分词,然后构建倒排索引,最后把数据转换成JSON格式存放在文档里。搜索过程是根据用户输入的关键字匹配倒排索引表中的文档集合,然后对文档进行评分,排序,高亮等处理,最后把搜索结果返回给用户。
ES全文搜索具体的步骤为:在上面爬虫模块中,已经从爬虫系统的pipeline中得到了经过去重处理之后返回的items对象,此时需要在pipeline中使用Elasticsearch-dsl将爬取到的items对象建立索引并保存到ES 中。当用户输入关键词进行搜索时,前端界面会根据关键词显示搜索建议,通过ES搜索建议接口Completion Suggester实现自动补全功能,后端接收到用户的搜索内容,经过数据分析,将关键词发送给ES服务器,并向ES数据库请求索引内容,最后将匹配到的文档集合返回给前端界面显示搜索内容。
食品安全搜索引擎页面的实现主要包括后端数据处理模块和前端数据可视化模块,主要用于用户输入搜索内容,返回搜索结果,及搜索结果的可视化。本文是基于Vue和Django搭建前后端分离的Web项目。使用前后端分离的思想主要是为了解耦合和网站的维护,以及之后可以在此食品安全搜索引擎的基础上完善其他有关食品安全的内容,搭建一个有关食品安全的信息网站。
5.1 后端数据处理模块
在本文中采用Django框架作为后端数据处理模块。Django是基于Python语言针对web后端开发的大型应用框架。它采用MVC的架构模式,M代表Model层(数据层),负责业务对象与数据库的对象关系映射(ORM)。C代表Controller(控制器),负责根据用户从”视图层”输入的指令,选取”数据层”中的数据,然后对其进行相应的操作,产生最终结果。V代表View层(视图层),它接受Web请求并且返回Web响应。
对于前端发送的数据请求,Django中间件(Middlewares)接收到用户请求并对request做一些预处理,通过URLconf模块查找对应的视图模块然后进行路由分发,对数据请求地址进行解析,视图层接收到请求,调用View中的函数,选择性的通过Models层访问数据库中的数据,将返回给Views层的输出经过Django中间件的处理,最后将Response返回给客户端,如图6所示。
图6 Django后端处理请求响应流程图
5.2 前端数据可视化模块
本文前端数据可视化模块采用基于MVVM架构模式的Vue框架。所谓MVVM架构,如下图7所示,Model代表模型层,主要实现数据的修改和操作业务逻辑;View代表视图层,主要负责将数据模型转化成可视化内容; ViewModel代表视图模型层,它是沟通模型层和视图层的桥梁所在。ViewModel层通过双向绑定的方式,当模型层发生改变时,ViewModel层监听到模型层的变化,并通知视图层发生改变,反之当视图层发生改变时会通知模型层改变。通过这种模式,可以更快地实现数据的响应以及视图的更新。
图7 MVVM架构
在实现搜索功能时,绑定搜索按钮点击事件HandleSearch,下面是前端实现搜索功能的主要程序:
5.3 食品安全搜索引擎搜索功能实现程序流程
在系统测试中爬取的目标选择了食品伙伴网(http://www.foodmate.net/),食品伙伴网中涵盖了大量关于食品安全信息的新闻资讯,网站结构上,反爬虫策略相对不是太难,页面结构也比较简单,很符合目前的要求。
关于爬取速度方面的测试,选用三台服务器,一台Master服务器和两台Slave服务器Master端:腾讯云服务器CPU 2核,2G内存,IP地址(49.233.21.252),centos7.5 64位系统; Slave端分别为: CPU 8核,8G内存,IP地址(192.168.43.199),Windows10 64位操作系统; CPU 2核,4G内存,IP地址(192.168.1.107),Ubuntun18.04 64位系统。以食品伙伴网为目标,运行60分钟,爬取到2282条数据。将爬取到的数据储存到Mysql数据库中。使用MySQLWorkbench可视化工具,展示部分数据如下所示:
针对去重清洗方面,经测试爬虫的日志信息提示丢掉约3%与已入库文本相似度较高的数据,经过确认,确实为重复数据。没有出现不能容忍的高误差数据。
搜索引擎界面如下所示:
搜索结果界面:
本文采用了Scrapy-redis分布式爬虫框架进行网络数据的爬取,然后经过布隆过滤器过滤URL及SimHash算法文本去重等一系列措施,实现对资源库的建立,基于Elasticsearch,构建全文搜索引擎,实现用户的快捷实时搜索。并使用Django+Vue前后端分离架构,实现了搜索引擎的可视化页面和交互。本文提出的思想是设想构建一款专门针对食品安全的信息网站,其中就有关于食品安全的全文搜索功能,未来还需要完善数据库资源,以及关于食品安全的不同数据资源。