鄭洪源



[摘 要]目前,在國內高校中程序設計課程的資源庫建設工作尚未普及,大多數教學資源存在較為嚴重的老舊、重復等問題,難以滿足師生日益增長的對大量新穎教學資源的需求。針對現在流行的網絡爬蟲框架進行分析和選擇,在現有框架的基礎上設計了一種適合資源庫建設的爬蟲系統,利用爬蟲的自動化特性完成教學資源庫的內容獲取及入庫工作。同時,選用Scrapy-redis對爬蟲進行拓展,利用Redis實現對目標網站資源的分布式爬取,提高獲取資源的速度。選用SimHash算法對爬取到的資源內容進行相似度判別,過濾掉相似度過高的資源,完成對資源庫的增量更新,提高獲取到的資源的質量。經測試,研究的系統初步滿足資源庫建設的自動化需求,能夠獲取有效的教學資源。
[關鍵詞]資源庫;網絡爬蟲;分布式爬取;SimHash算法
[中圖分類號] G64 [文獻標識碼] A [文章編號] 2095-3437(2019)09-0076-04
無論在國內還是國外,計算機類學生必修的程序設計這門課程對于教學資源及時更新的需求益發迫切,太過陳舊的教學資源和試題不利于對學生的培養。由于學生可以在考前通過各種途徑獲取歷年考試真題,通過記憶考試題目便可以獲得高分。考題陳舊、相似度高,使得考試環節的權威性、有效性大打折扣,這不利于檢驗學生的真實水平,也會導致教師教學資源的缺乏。
教學資源庫的建設目標是以為師生的教與學提供優質服務為最終目的,以整合教學資源為主要方法,使得教師在備課過程中更加高效、更加充實,讓學生在課下學習時更加自由、更加便捷。其發展趨勢主要呈以下兩個特點:1.資源選擇便捷化。教師利用本學科的資源庫充實課程內容時,將可以更加快捷地對資源庫進行篩選。節約教師查找內容的時間,提高獲取合適資源的準確度,使教師有更多的時間去創新,反向充實資源庫,形成良性循環。2.系統服務個性化。針對教師的教學內容、課程對學生等級、學習階段等的不同要求,根據對教師信息的匯總和系統識別,為教師提供滿足自身需求的準確服務,提高系統資源的可用性。
一、目的和意義
本研究利用主題網絡爬蟲不需要訪問數據庫,自動抓取頁面信息的特性,對程序設計資源庫的建設進行探索和實踐[1]。通過對目標網站的分析和爬取,實現資源聚合,完成資源庫在內容上從無到有的突破。通過對當下流行的一些技術進行實際的開發和應用,為以后構建功能更加完善的資源庫系統提供非常有用的實踐經驗。同時,本文雖然是針對程序設計課程資源庫建設開展研究,但研究方法考慮通用性,只需通過主題庫和爬取規則更新,就可以適用于其他課程的資源建設中。
二、系統總體架構
本系統被設計為三個模塊。分別為:爬蟲模塊,API模塊和數據可視化模塊,系統架構如圖1所示。
本系統通過爬取特定的URL,下載其標識的資源頁面,從互聯網中獲取所需的信息。并在爬蟲模塊中借用Redis進行信息文本的清洗、組合、判重等操作。最后將合格的資源存入MongoDB數據庫中,API則根據數據可視化的要求,通過對MongoDB數據庫中的已存信息進行查詢等操作,實現對應API功能[2]。數據可視化模塊則同過調用API獲取數據,在瀏覽器中對數據進行加工和展示,使師生用戶可以無障礙使用本系統。
三、爬蟲模塊設計
爬蟲模塊在Scrapy和Scrapy-redis組件的基礎上,進行功能拓展和實現。又分為多個子模塊,包括:控制子模塊,url重復過濾模塊,頁面解析模塊,文本相似過濾模塊,存儲模塊[3]。整個模塊結構如圖2所示。
(一)控制子模塊
本模塊是在Scrapy-Redis組件中所實現的調度器、爬蟲等類的基礎上,通過定義重載一些方法實現對爬蟲的個性化控制[4]。其控制流程如圖3所示。
爬蟲啟動后,會首先運行spider類中的start_requests方法,在該方法中,我們進行主從模式的判斷,如果是主模式,則要進一步判斷是否已有Cookies,如果沒有,則需要同過Selenium模擬瀏覽器登錄目標網站獲取Cookies,并將Cookies存儲于Redis中,共享給從模式啟動的爬蟲使用。Cookies生成之后,主模式下會生成待爬取的初始請求隊列,然后進入頁面的爬取解析循環。對于從模式啟動的爬蟲,則直接進入頁面的爬取解析循環,如果沒有待爬取的請求,則等待。經過頁面解析之后,將提取后的結構化數據通過存儲子模塊進行存儲。其中,對于新產生的URL和新提取的數據都要經過重復過濾,合格的URL和數據才能進入下一步流程當中[5]。
(二)URL重復過濾模塊
該模塊主要實現了Bloom Filter算法,并把它與實際爬蟲應用結合起來。將Scrapy-redis原有的利用Redis集合特性的去重模塊進行替換。算法和調用接口的具體實現主要在DBloomFilter類中完成,該類類圖如圖4所示。
其中,SEEDS屬性是Bloom Filter算法所需要的哈希函數的隨機種子。m是位數組的位數,k是哈希函數的個數,conn是Redis連接的實例,key是Redis中存儲位數組的鍵名,由于Redis中最大只支持512M的位數組,為了在海量數據下依然能保證較高的正確率,將超過512M大小的位數組進行分塊處理,mem屬性是512M分塊的個數,blocknum是每個分塊的編號[6]。
init方法初始化Bloom Filter所需的各種參數m,k,conn 等。
getHashs則是對傳進來的參數使用k個不同的哈希函數,獲得k個哈希值,即該URL在位數組中的位置。
isExist方法是提供給爬蟲判斷URL是否已經爬取了的方法,接受需要去重的數據作為參數,調用getHashs方法獲得URL的k個哈希值,并判斷位數組中是否已經存在。存在返回True,不存在返回False。
add方法是提供給其他模塊向位數組中加入該URL記錄的方法。
(三)頁面解析模塊
頁面解析模塊主要是對Spider類的拓展和實現。類圖如圖5所示。
頁面解析模塊主要是兩個解析方法,listParse方法主要解析爬取來的列表頁面。根據列表頁中的資源id再進行構造對應資源的URL。problemParse則是對具體資源頁面的解析,通過Scrapy提供Item解決方案,提取組合成結構化的數據,暫時組織在Item類的實例中。
(四)文本相似過濾模塊
該模塊是基于Scapy提供的Item pipelies組件機制實現的。通過編寫pipeline組件,并規定它的執行順序,實現對頁面解析模塊獲得的結構化數據進行詳細過濾[7]。頁面解析模塊最終生成包含數據的Item實例,并把它轉交這Item pipeline中,pipeline組件有序地對Item進行處理。
DDupefilterPipeline是實現的組件類。當Item通過時,它調用Simhash類提供的方法,對Item中的特定字段進行相似度判別。對于擁有和已經入庫的數據較高相似度的Item將被丟棄。只有相似度合格的Item才能進入下一個pipeline組件中。
SimHash類是實現SimHash算法的工具類。它的類圖如圖6所示。
該類的兩個屬性會在初始化時賦值,hashBitNum是生成的哈希值的長度。maxKeywordWeight是關鍵詞權重值的最大值[8]。
simHash方法通過調用jieba分詞的分詞方法,對文本content進行分詞,并從中提取帶有權重值的關鍵詞列表,把得到的列表交給hashFeature方法。在hashFeature方法中,實現了SimHash算法里所講的流程,最終得到了該文本的SimHash值。
is_equal方法是用來判斷兩個文本的相似度的,通過調用hmDistance方法,得到兩個SimHash值的漢明距離,來判斷相似度是否超過給定的上限。如果超過則返回True,否則返回False。
hashFunc和tokenizerFunc方法則是算法需要的哈希函數方法和分詞方法[9]。
在具體去重中,DDupefilterPipeline類的process_item方法會先調用simHash方法,獲取Item中給定字段的SimHash值。判斷這個值是否已經在Redis數據庫中,如果不存在則調用is_equal方法,與Redis數據庫中的每一個SimHash進行對比,相似度高于上限的直接丟棄,相似度合格的則把該SimHash值存入Redis中,并將該Iten傳入下一個pipeline組件中。
(五)存儲子模塊
和文本相似過濾模塊相似,存儲子模塊通過pipeline組件,對經過去重的Item進行存儲操作。DMongodbPipeline類通過調用pymongo提供的API接口,完成對MongoDB的連接等操作。完成對有效數據的插入。
由于MongoDB是非關系型數據庫,和傳統的關系型數據庫相比,它是以BSON文檔作為基本的數據模型,沒有表的概念。在MongoDB中,一個數據庫可以包含多個集合,一個集合包含了同類文檔,文檔中又可以嵌套文檔、數組和文檔數組[10]。
在本系統中MongoDB數據庫主要有兩個集合:problems和knowledgePoints。
四、API模塊
API模塊使用Koa2.js框架進行開發,為數據可視化模塊提供獲取數據的API接口。它的主要功能就是接收客戶端應用發來的http請求,從中提取有效安全的參數,在數據庫中完成數據的查詢,并將數據返回給客戶端應用。
Koa2.js框架是基于NodeJS平臺的下一代Web開發框架,是由 Express 原班人馬打造的,致力于成為一個更小、更富有表現力、更健壯的 Web 框架。 使用JavaScript編寫應用時,會面臨重復煩瑣的“回調地獄”問題。在Koa2中通過組合不同的 generator,可以避免這一問題,并極大地提升錯誤處理的效率。Koa2為了保證自身的簡潔性,自身內核除了關鍵內容以外,把路由、解析等功能都被用中間件的形式來實現,它僅僅提供了一個輕量優雅的函數庫,使開發者在編寫 Web 應用更加得心應手。
整個流程看起來很像洋蔥,但并不是一層一層地執行,而是以中間件調用next方法的地方為界,當請求Request傳來時,先一次執行每個中間件next之前的部分,當下一層中間件執行完后,再執行本層next后的部分[11]。
通過在koa-router中間件中定義API路由,并指定匹配到該路由時的應該執行的回調函數。在回調函數中進行數據庫查詢,并對該請求進行響應,返回數據。所有的回調函數按功能被組織在特定的Controller類中。
ProblemController類主要完成了目前階段所有API的回調函數的定義和實現。其類圖如圖7所示。
getProblemByType方法中實現了按條件對數據庫進行檢索,并利用MongoDB的skip、limit、sort等方法以及_id的特性,實現了分頁查詢,比單獨使用skip和limit方法實現分頁有了更好的性能,尤其是數據量龐大時。getKnowledgePoints則是返回了當前知識點的子知識點。
五、系統測試
關于爬取速度方面,經測試,在單機條件下運行,爬蟲持續運行無報錯,穩定持續爬取數據。90分鐘入庫數據3140條,平均35條/min。
在爬取完整性方面,針對某網站最終需要爬取5835個頁面,共爬取5835個頁面,實現全部爬取無遺漏。最終數據庫有4886條數據,有949條數據被判定相似或重復。
針對相似度過濾方面,經測試爬蟲系統的log信息提示丟棄掉了約5%和已入庫文本相似度極高的文本,經過系統比對規則確認,這部分確實屬于重復資源,系統予以舍棄,不做重復入庫。當數據庫中存入了多條相似,但要求實現不同函數的問題,證明文本相似過濾模塊運行性能在預期內,沒有出現不能容忍的高誤判率。
六、總結
本文采用了穩定性及拓展性良好的Scrapy/Scrapy-redis框架,實現對數據的清洗,去重以及入庫等操作。運用Downloader Middleware機制對發出的爬取請求進行定制,同時對服務器的響應進行識別,對不同的響應狀態碼進行不同的處理。為了實現分布式爬取而采取的Redis數據庫操作的原子性和基于內存的特性發揮了極大的性能優勢。經測試,資源庫系統各方面表現穩定,擁有良好的可拓展性,滿足設計需求。
值得進一步探索改進之處主要表現在,目標網站的反爬機制對爬蟲系統有一定限制。目標網站為限制同一IP在短時間內的請求數,為了保證爬取的準確度,爬蟲不得不進行自我休眠,限制了爬取速度。可以通過增加機器、選用優秀穩定的代理池去解決。
[ 參 考 文 獻 ]
[1] 陳永彬. 基于聚焦爬蟲技術的教學資源搜集與自動整理方法研究[D]. 東北師范大學,2011.
[2] 陳昭穩. 基于網絡爬蟲軟件建設主題網絡信息資源庫的研究——以高鐵網絡信息資源庫建設為例[J]. 安徽電子信息職業技術學院學報,2014(6):12-14.
[3] 郭小丹. 幾種開源網絡爬蟲功能比較[J]. 黑龍江科技信息,2015(25):154.
[4] 劉建明. 垂直搜索引擎中的主題爬蟲技術研究[D].廣東工業大學,2013.
[5] 金斯特. 基于Web 挖掘的主題搜索引擎網頁抓取策略的研究[D]. 浙江工業大學,2014.
[6] Yuhao Fan. Design and Implementation of Distributed Craw-ler System Based on Scrapy[J]. IOP Conference Series:Ea-rth and Environmental Science,2018,108(4).
[7] Luo L, Guo D, Ma R T B, et al. Optimizing Bloom Filter: Challenges, Solutions, and Comparisons[J]. arXiv:1804.04777v2[CS.DS] 7 Jan 2019:10-32.
[8] Manku G S,Jain A,Sarma A D. Detecting near-duplicates for web crawling[C] International Conference on World W-ide Web. ACM,2007:141-150.
[9] Jain A, Manku G S. Near-duplicate document detection for web crawling: US,US8140505[P]. 2012.
[10] Haber,Itamar. MongoDB and Redis pair volume with velocity[J]. InfoWorld.com,2015.
[11] 程桂花,沈煒,何松林,等. Node.js中Express框架路由機制的研究[J]. 工業控制計算機,2016(8):101-102.
[責任編輯:黃緊德]