董 哲 祝福松
(北方工業大學 電氣與控制工程學院,北京 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前后端分離架構,實現了搜索引擎的可視化頁面和交互。本文提出的思想是設想構建一款專門針對食品安全的信息網站,其中就有關于食品安全的全文搜索功能,未來還需要完善數據庫資源,以及關于食品安全的不同數據資源。