高文超 李浩源 徐永康
摘要:隨著信息量的增多,為用戶提供便捷的搜索服務(wù)也更加具有挑戰(zhàn)性。大規(guī)模存儲(chǔ)信息并精確搜索的代價(jià)是巨大的,人們需要在信息搜索的快捷性與成本中找到平衡。系統(tǒng)實(shí)現(xiàn)一個(gè)基于網(wǎng)絡(luò)爬蟲的搜索引擎。軟件結(jié)構(gòu)分為爬蟲部分,數(shù)據(jù)庫部分,前端顯示部分。同時(shí),描述了擴(kuò)展成分布式爬蟲的方法。硬件方面需要多臺(tái)主機(jī),軟件方面包括Scrapy爬蟲、數(shù)據(jù)庫、Django框架。最終設(shè)計(jì)并實(shí)現(xiàn)了一個(gè)具有良好的健壯性和擴(kuò)展性的網(wǎng)絡(luò)爬蟲系統(tǒng)。
關(guān)鍵詞:爬蟲;信息;搜索引擎;數(shù)據(jù)庫;Web框架
中圖分類號(hào):TP393? ? ? 文獻(xiàn)標(biāo)識(shí)碼:A
文章編號(hào):1009-3044(2020)30-0006-04
Abstract: In the Internet era, with an increasing amount of information, it is more challenging to provide users with convenient search services. The cost of storing information on a large scale and searching accurately is huge, and people need to balance the speed and cost of information searching. This system implements a search engine based on a web crawler. The software structures are divided into the crawler part, database part, and front-end display part. At the same time, it describes the method to expand into a distributed crawler. In terms of hardware, multiple hosts are needed. In terms of software, Scrapy crawlers, databases, and the Django framework. Finally, a web crawler system with good robustness and expansibility is designed and implemented.
Key words: Reptile; information; Search Engines; database; web framework
1 背景
身處于信息時(shí)代,數(shù)據(jù)共享與查詢越來越便捷,基于數(shù)據(jù)的服務(wù)也越來越多,各行各業(yè)越來越依賴于爬蟲對數(shù)據(jù)進(jìn)行提取[1]。但是,隨著信息數(shù)據(jù)量迅速增長,這些數(shù)據(jù)中包含著許多模糊不清的信息,構(gòu)成了一個(gè)龐大的網(wǎng)絡(luò)資源庫。因此人們需要從海量數(shù)據(jù)中提取所需要的信息,同時(shí)平衡成本。爬蟲能夠?qū)⒂脩羲枰臄?shù)據(jù)提取出來,但是僅僅依靠單機(jī)爬蟲,采集速度難以處理繁多的頁面,而硬件的發(fā)展也無法跟上信息量的增長。因此,合理限定抓取范圍,開發(fā)面向與各個(gè)領(lǐng)域的輕量化搜索引擎,擴(kuò)展單機(jī)爬蟲為分布式爬蟲都是可行的解決方法。
2 總體設(shè)計(jì)與功能
2.1 功能設(shè)計(jì)
一個(gè)單詞在不同領(lǐng)域具有不同含義,用戶直接在通用搜索引擎上搜索可能會(huì)顯示完全不同的結(jié)果。需要精細(xì)化搜索引擎范圍,本系統(tǒng)開發(fā)一套面向于某一領(lǐng)域和中小企業(yè)的搜索引擎,具有數(shù)據(jù)范圍相對較集中,數(shù)據(jù)量相對較小的特點(diǎn)。
通過對需求的分析,將該搜索引擎分為兩個(gè)頁面。其一是搜索網(wǎng)站搜索主頁,包括搜索分類選擇、輸入框輸入信息并搜索、熱門搜索與搜索記錄共同組成了搜索門戶方便用戶搜索,其二是搜索網(wǎng)站結(jié)果顯示頁,在該頁面上顯示搜索的相關(guān)信息,搜索輸入框,滿足用戶信息瀏覽和繼續(xù)搜索的需求。第一部分,將搜索的信息分為幾個(gè)板塊,用戶可以選擇不同板塊來進(jìn)行對應(yīng)的搜索。第二部分,在頁面上顯示熱門搜索和歷史記錄,用戶可以點(diǎn)擊對應(yīng)的關(guān)鍵字進(jìn)入對應(yīng)的結(jié)果頁鏈接。在顯示搜索結(jié)果的時(shí)候,顯示搜索標(biāo)題、簡介、結(jié)果數(shù)據(jù)統(tǒng)計(jì)信息等,方便用戶瀏覽。
2.2 模型設(shè)計(jì)
本系統(tǒng)采用B/S架構(gòu),服務(wù)器作為核心事物的重要部分[2]。后端框架選用Django搭建,前端頁面通過嵌入來顯示網(wǎng)頁,并在Django框架中設(shè)置數(shù)據(jù)處理函數(shù)處理數(shù)據(jù)庫中的信息。
本系統(tǒng)設(shè)計(jì)針對某領(lǐng)域提供信息,不同用戶搜索的內(nèi)容可能有不同的爬蟲爬取,相同的搜索領(lǐng)域由同類型的爬蟲抓取數(shù)據(jù)。所有抓取的數(shù)據(jù)信息根據(jù)不同數(shù)據(jù)庫的特點(diǎn)分別保存。
作為一個(gè)系統(tǒng),穩(wěn)定是最重要的因素,因此需要考慮穩(wěn)定運(yùn)行,數(shù)據(jù)備份等因素,此外需要具有良好的可拓展性,能夠隨著用戶增長的需求來擴(kuò)充數(shù)據(jù)的范圍,因此代碼的編寫需要規(guī)范化,方便后期維護(hù)升級(jí)。
本系統(tǒng)分為三部分,包括爬蟲部分,存儲(chǔ)部分和顯示部分。各部分功能與主要技術(shù)設(shè)計(jì)如圖1所示:
1)爬蟲部分:該模塊用于爬取目標(biāo)網(wǎng)站信息,包括實(shí)現(xiàn)自動(dòng)登錄,設(shè)置措施突破反爬限制,設(shè)置網(wǎng)頁爬取策略根據(jù)不同網(wǎng)站特點(diǎn)爬取對應(yīng)信息,數(shù)據(jù)字段提取與保存信息等功能。
2)存儲(chǔ)部分:該模塊的功能是將爬蟲爬取的信息分別存儲(chǔ)到不同的數(shù)據(jù)庫中。MySQL數(shù)據(jù)庫用來存儲(chǔ)單機(jī)上爬取的信息,并作為備份。Elasticsearch數(shù)據(jù)庫用于匯總存儲(chǔ)數(shù)據(jù)并構(gòu)建索引。Redis數(shù)據(jù)庫是內(nèi)存數(shù)據(jù)庫,存取數(shù)據(jù)十分迅速,用于保存常用信息,同時(shí)作為分布式爬蟲隊(duì)列管理工具。
3)顯示部分:本模塊設(shè)置服務(wù)端處理數(shù)據(jù)的過程,使用基于Python的Django框架。選擇B/S架構(gòu),同時(shí)將處理后的數(shù)據(jù)在瀏覽器頁面上顯示。后端框架選取MVT模式。
3 詳細(xì)實(shí)現(xiàn)
3.1 爬蟲的實(shí)現(xiàn)
1)爬蟲規(guī)則設(shè)計(jì)
本系統(tǒng)實(shí)現(xiàn)的爬蟲基于Scrapy框架,在爬蟲模塊中主要完成爬取目標(biāo)網(wǎng)站的功能。根據(jù)不同網(wǎng)站的結(jié)構(gòu),選取深度優(yōu)先策略和廣度優(yōu)先策略[3]。設(shè)計(jì)信息解析模塊,對目標(biāo)網(wǎng)站的布局與邏輯進(jìn)行分析,發(fā)現(xiàn)網(wǎng)站網(wǎng)頁結(jié)構(gòu)主要可以分為主頁、列表頁、詳情頁。網(wǎng)站的主頁設(shè)為網(wǎng)站的一級(jí)頁面,是用戶進(jìn)入網(wǎng)站的入口。所有內(nèi)部頁面可以通過主頁上的鏈接進(jìn)行訪問。網(wǎng)站的列表頁是二級(jí)頁面,負(fù)責(zé)網(wǎng)站某一分類下的所有相關(guān)頁面的URL信息。詳情頁定義為三級(jí)頁面,是用戶訪問該網(wǎng)站的目標(biāo)頁面,同時(shí)也是爬蟲主要抓取對象和信息提取頁。整個(gè)過程如圖2。
2)數(shù)據(jù)處理模塊
首先定義爬蟲名稱,爬取的域名和起始頁面。其次,獲取網(wǎng)頁列表頁URL,下載后使用parse函數(shù)處理,同時(shí)定理next_url來循環(huán)爬取其他URL。然后在詳情頁面上具有大部分的目標(biāo)信息,針對這些信息,使用CSS和XPATH選擇器提取頁面詳細(xì)信息。部分字段提取樣式如表1:
①動(dòng)態(tài)頁面加載:部分網(wǎng)頁并不會(huì)一次性顯示全部數(shù)據(jù)信息,需要通過鼠標(biāo)下滑或者點(diǎn)擊對應(yīng)按鈕才能夠查看并顯示更多內(nèi)容。編寫process_request函數(shù),調(diào)用browser.execute_script方法控制網(wǎng)頁下滑來進(jìn)行動(dòng)態(tài)網(wǎng)頁解析。
②存儲(chǔ)部分:爬蟲在一段時(shí)間內(nèi)訪問網(wǎng)站次數(shù)過多,其IP地址會(huì)被網(wǎng)站識(shí)別重定向或封禁。使用IP代理池隨機(jī)更換IP地址防止網(wǎng)站識(shí)別[4]。定義GetIP類來實(shí)現(xiàn)對IP地址的控制,此類包含兩個(gè)函數(shù),delete_ip(self,ip)用來從數(shù)據(jù)庫中刪除無效IP。judge_ip(self,ip,port)用來判斷IP是否可用。
③模擬登錄的設(shè)計(jì):部分網(wǎng)站需要進(jìn)行登錄才能訪問網(wǎng)站信息,同時(shí)登錄過程中可能會(huì)需要輸入驗(yàn)證碼。對于針對這一部分網(wǎng)站,首先在CMD中啟動(dòng)遠(yuǎn)程調(diào)試打開瀏覽器防止識(shí)別出WebDriver。加載瀏覽器驅(qū)動(dòng)啟動(dòng)瀏覽器。最大化界面并定位輸入框與按鈕,在登錄界面使用選擇器定位登陸元素和查找用戶名密碼輸入框,使用Selenium自動(dòng)輸入預(yù)設(shè)信息并登錄[5]。最后,如果在網(wǎng)頁上找到對應(yīng)信息則判斷登陸成功。具體登錄流程如下:
4)分布式爬蟲改進(jìn)方案
本系統(tǒng)采用主從結(jié)構(gòu),包含一個(gè)控制節(jié)點(diǎn)和一個(gè)爬行節(jié)點(diǎn)具體方法如下:
①安裝依賴包,例如Scrapy和Scrapy-Redis等。
②構(gòu)建分布式爬蟲系統(tǒng)。增加dupefilter.py文件實(shí)現(xiàn)去重,替換Scheduler調(diào)度器。
③修改Spider組件,指定Redis_Key并在Spider繼承動(dòng)態(tài)網(wǎng)頁加載功能。
④修改配置文件,添加數(shù)據(jù)連接功能,配置本機(jī)端口和地址。修改Pipeline.py在ITEM_PIPELINES中添加scrapy_redis.pipelines.RedisPipeline,將爬取的信息存入Redis 數(shù)據(jù)庫。
⑤集成BloomFilter過濾器,在大型爬蟲中用于URL去重[7]。本系統(tǒng)中過濾器通過add函數(shù)添加元素,is_exist函數(shù)查詢,get_hashs函數(shù)用來取得哈希值。
3.2 數(shù)據(jù)庫的實(shí)現(xiàn)
1)數(shù)據(jù)庫總體設(shè)計(jì)
部分本系統(tǒng)數(shù)據(jù)庫分為三種,MySQL數(shù)據(jù)庫負(fù)責(zé)單機(jī)爬蟲數(shù)據(jù)的備份。Redis內(nèi)存數(shù)據(jù)庫負(fù)責(zé)保存與修改常用數(shù)據(jù)。Elasticsearch數(shù)據(jù)庫負(fù)責(zé)人構(gòu)建索引,支持搜索引擎功能。三種數(shù)據(jù)庫共同構(gòu)成本項(xiàng)目的數(shù)據(jù)庫模塊。
2)數(shù)據(jù)庫表的設(shè)計(jì)
以某網(wǎng)站新聞板塊為例,通過分析爬取目標(biāo)來設(shè)置數(shù)據(jù)庫的字段。同時(shí)實(shí)現(xiàn)數(shù)據(jù)存儲(chǔ)的安全性,設(shè)置Mysql Twisted Pipeline使用異步入庫方式。以新聞模塊為例,數(shù)據(jù)庫表如下所示:
3)ES數(shù)據(jù)庫建立
①在數(shù)據(jù)庫中,定義數(shù)據(jù)庫的名稱,分片數(shù)量[8]。然后建立索引,通過Mappings函數(shù)將輸入數(shù)據(jù)轉(zhuǎn)變成可以搜索到的索引項(xiàng),通過Kibana調(diào)試。
②建立索引與映射,在工程中的Models包里的es_type.py來建立的,它可以用來控制數(shù)據(jù)向ES的寫入。設(shè)置Meta信息。在其中定義這些數(shù)據(jù)存儲(chǔ)的索引index名并設(shè)置文檔類型doc_type方便前端網(wǎng)頁分類。在pipelines.py中定義ElasticsearchPipeline類將數(shù)據(jù)寫入ES中。在這個(gè)類下定義process_item函數(shù)實(shí)現(xiàn)將item類轉(zhuǎn)換為ES數(shù)據(jù)。
4)Redis數(shù)據(jù)庫建立
為了加快對常用數(shù)據(jù)的存取速度,本系統(tǒng)將統(tǒng)計(jì)各網(wǎng)站爬取頁面的計(jì)數(shù)器存入Redis數(shù)據(jù)庫中。在Scrapy框架中Redis數(shù)據(jù)庫的主要工作是統(tǒng)計(jì)網(wǎng)頁總數(shù)。在items.py文件中設(shè)置,在每次往ES存入一個(gè)數(shù)據(jù)的時(shí)候,使用redis_cli函數(shù)中incr方法,對不同類型的文章存儲(chǔ)時(shí)進(jìn)行計(jì)數(shù),使得Redis中存儲(chǔ)了每種類型文章的數(shù)量。
對于Scrapy-Redis框架,修改對應(yīng)的措施,實(shí)現(xiàn)分布式爬蟲的要求。首先在Scrapy-Redis功能配置的defaults文件中設(shè)置REDIS_CLS=redis.StrictRedis可以提供對Redis集群操作的方法。然后添加Redis配置,對DOWNLOADER_MIDDLEWARES,SCHEDULER和ITEM_PIPELEINES分別設(shè)置對應(yīng)的措施滿足分布式爬蟲的要求。最后在connection中添加Redis集群實(shí)例化的措施。
3.3 服務(wù)端的實(shí)現(xiàn)
本系統(tǒng)中,服務(wù)端作為關(guān)鍵模塊之一,負(fù)責(zé)對輸入文本進(jìn)行處理,與數(shù)據(jù)庫進(jìn)行交互,處理數(shù)據(jù)并返回結(jié)果到前端頁面上。主要流程如下:
1)導(dǎo)入靜態(tài)頁面,搭建兩個(gè)靜態(tài)頁面模板,命名為index和result放入新建工程的templates文件夾下,將圖片資源放入static文件夾。在urlpatterns中配置靜態(tài)頁面的路徑。
2)實(shí)現(xiàn)搜索推薦功能。在index頁面完成搜索建議函數(shù),使用get方法獲取輸入文本,與搜索類型s.type共同組成請求。在視圖中定義SearchSuggest類在類中處理文本,后端根據(jù)輸入內(nèi)容匹配補(bǔ)全字段。
3)搜索結(jié)果顯示。在view.py定義SearchView類,將后臺(tái)信息傳遞給前端,取得關(guān)鍵詞匹配高亮處理,設(shè)置每頁顯示結(jié)果數(shù)。并將數(shù)據(jù)庫中主要信息傳給前端頁面對應(yīng)位置顯示。
4)搜索記錄與熱門搜索顯示。定義add_search函數(shù)存儲(chǔ)搜索數(shù)據(jù),把數(shù)組存儲(chǔ)到瀏覽器本地。統(tǒng)計(jì)搜索次數(shù)并按照時(shí)間順序顯示歷史記錄。熱門搜索需要調(diào)用Redis數(shù)據(jù)庫中的sortedSet集合,通過ZINCRBY命令實(shí)現(xiàn)搜索數(shù)量記錄。最后返回高頻搜索關(guān)鍵字。
4 系統(tǒng)結(jié)果展示
4.1 開發(fā)環(huán)境的展示
本系統(tǒng)中,主要工具的版本號(hào)如下表所示:
4.2 門戶起始頁展示
用戶進(jìn)入搜索引擎起始頁面index.html,可以選擇搜索模塊,并在搜索框中輸入文本,文本內(nèi)容每次變化則會(huì)觸發(fā)一次搜索,在數(shù)據(jù)庫中查找匹配項(xiàng)并顯示。也可以瀏覽并點(diǎn)擊熱門搜索和搜索記錄中的關(guān)鍵詞。
4.3 搜索結(jié)果頁展示
點(diǎn)擊搜索按鈕之后網(wǎng)站轉(zhuǎn)到結(jié)果顯示界面result.html。信息按照相關(guān)度得分排序,同時(shí)將匹配字符標(biāo)紅。
點(diǎn)擊搜索按鈕之后網(wǎng)站轉(zhuǎn)到結(jié)果顯示界面。信息按照相關(guān)度得分排序,將匹配字符標(biāo)紅。同時(shí)顯示網(wǎng)站數(shù)量和搜索附加信息。
4.4 后臺(tái)數(shù)據(jù)展示
MySQL數(shù)據(jù)庫保存各臺(tái)主機(jī)爬取信息,作為備份保存數(shù)據(jù)。以職位網(wǎng)站為例,單機(jī)抓取有效網(wǎng)頁數(shù)量600余條,本系統(tǒng)隨機(jī)抓取延遲時(shí)間范圍5-15秒。理論上每小時(shí)可抓取360個(gè)網(wǎng)頁,2小時(shí)可抓取720個(gè)網(wǎng)頁。但由于網(wǎng)絡(luò)帶寬和隨機(jī)延遲,導(dǎo)致抓取數(shù)量減少。存儲(chǔ)數(shù)據(jù)如下所示:
5 總結(jié)與展示
本文主要實(shí)現(xiàn)基于Scrapy網(wǎng)絡(luò)爬蟲的搜索引擎。該系統(tǒng)可滿足中小企業(yè)或某一領(lǐng)域范圍內(nèi)的搜索需求。本系統(tǒng)具有擴(kuò)展性強(qiáng)、穩(wěn)定性高等特點(diǎn)。但是,本系統(tǒng)在單機(jī)上搭建了分布式爬蟲,并未考慮實(shí)際中不同服務(wù)器節(jié)點(diǎn)性能存在差異等問題,同時(shí)針對部分網(wǎng)站,應(yīng)該基礎(chǔ)研究設(shè)置更加合理的爬取策略,降低網(wǎng)站反爬偵測的概率,提升系統(tǒng)的性能。
參考文獻(xiàn):
[1] 樊宇豪.基于Scrapy的分布式網(wǎng)絡(luò)爬蟲系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)[D].成都:電子科技大學(xué),2018.
[2] 王貴智.基于B/S智慧教務(wù)綜合管理系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[D].長沙:湖南大學(xué),2019.
[3] 王芳,張睿,宮海瑞.基于Scrapy框架的分布式爬蟲設(shè)計(jì)與實(shí)現(xiàn)[J].信息技術(shù),2019,43(3):96-101.
[4] 余豪士,匡芳君.基于Python的反爬蟲技術(shù)分析與應(yīng)用[J].智能計(jì)算機(jī)與應(yīng)用,2018,8(4):112-115.
[5] 馮興利,洪丹丹,羅軍鋒,等.基于Selenium+Python的高校統(tǒng)一身份認(rèn)證自動(dòng)化驗(yàn)收測試技術(shù)研究[J].現(xiàn)代電子技術(shù),2019,42(22):89-91,97.
[6] 梁浩喆,馬進(jìn),陳秀真,等.現(xiàn)代瀏覽器中Cookie同源策略測試框架的設(shè)計(jì)與實(shí)現(xiàn)[J].通信技術(shù),2019,52(12):3039-3045.
[7] 孟慧君.基于Bloom Filter算法的URL去重算法研究及其應(yīng)用[D].開封:河南大學(xué),2019.
[8] 王磊,王胤然,徐寅,等.一種ElasticSearch分片擴(kuò)展方法:CN108509438A[P].2018-09-07.
【通聯(lián)編輯:謝媛媛】