◆郭慧珍 劉雨澤 梁燁文 王 哲 宋佳音
面向民航售票網(wǎng)站的實時爬蟲系統(tǒng)的設(shè)計與實現(xiàn)
◆郭慧珍 劉雨澤 梁燁文 王 哲 宋佳音
(中國民航大學(xué)計算機科學(xué)與技術(shù)學(xué)院 天津 300300)
近年來,隨著互聯(lián)網(wǎng)、大數(shù)據(jù)、信息化以及電子商務(wù)等計算機技術(shù)相關(guān)領(lǐng)域日新月異的發(fā)展,互聯(lián)網(wǎng)上存在著大量的可利用的有效信息。隨著這些技術(shù)的發(fā)展,爬蟲技術(shù)也得到了廣泛的應(yīng)用而快速發(fā)展,實現(xiàn)了有效信息快速高效的采集和整合,本文介紹了面向民航售票網(wǎng)站的實時爬蟲系統(tǒng)的設(shè)計與實現(xiàn),供讀者參考。
網(wǎng)絡(luò)爬蟲;Scrapy框架;MongoDB數(shù)據(jù)庫
隨著我國綜合國力和人們生活水平的提高,飛機已經(jīng)成為人們重要的出行方式之一。但是不同于傳統(tǒng)的鐵路運輸方式,很多時候航空公司會提供價格較低的機票,以促進(jìn)銷售額或為旅客提供性價比更高的服務(wù)。但是大多數(shù)時候,機票信息紛繁復(fù)雜,旅客無法準(zhǔn)確及時獲取打折機票的信息。顯然,如何及時有效的整理當(dāng)前折扣機票,為旅客提供更為直觀、有效的購票信息閱覽體驗成為值得探索的話題。因此,實現(xiàn)信息獲取和整合是我們要完成的主要任務(wù)。網(wǎng)絡(luò)爬蟲是一種按照一定的規(guī)則,自動地抓取萬維網(wǎng)信息的程序或者腳本,它們被廣泛用于互聯(lián)網(wǎng)搜索引擎或其他類似網(wǎng)站,可以自動采集所有其能夠訪問到的頁面內(nèi)容,以獲取或更新這些網(wǎng)站的內(nèi)容和檢索方式。
為了提高系統(tǒng)的效率,同時對多個任務(wù)加以控制,在同一時間需要完成多項任務(wù),本系統(tǒng)中使用Scrapy框架來實現(xiàn)多線程。Scrapy是用純Python實現(xiàn)一個為了爬取網(wǎng)站數(shù)據(jù)、提取結(jié)構(gòu)性數(shù)據(jù)而編寫的應(yīng)用框架。Scrapy使用了 Twisted異步網(wǎng)絡(luò)框架來處理網(wǎng)絡(luò)通訊,可以加快我們的下載速度,不用自己去實現(xiàn)異步框架,并且包含了各種中間件接口,可以靈活完成各種需求[1]。
Splash是Scrapy官方推薦的JavaScript渲染,它是使用WebKit開發(fā)的輕量級無界面瀏覽器,提供基于HTTP接口的JavaScript渲染服務(wù)。XPath即為XML路徑語言(XML Path Language),它是一種用來確定XML文檔中某部分位置的語言。本系統(tǒng)中,依次,使用Splash渲染技術(shù)和xpath提取全部需要的機票相關(guān)的數(shù)據(jù)內(nèi)容。使用Splash渲染技術(shù),對需要獲取到的票價等機票數(shù)據(jù)進(jìn)行分析,當(dāng)頁面加載完成時需要的機票數(shù)據(jù)可以被加載出來。下一步,使用XPath提取頁面的信息,以航空公司名稱為例在谷歌瀏覽器使用XPath進(jìn)行初步提取[2]。
MongoDB是NoSQL(非關(guān)系型數(shù)據(jù)庫)中的一類文檔型數(shù)據(jù)庫,其數(shù)據(jù)存儲方式靈活。MongoDB也很好地實現(xiàn)了面向?qū)ο蟮乃枷?,在MongoDB中,每一條記錄都是一個Document對象。MongoDB最大的優(yōu)勢在于所有的數(shù)據(jù)持久操作都無須開發(fā)人員手動編寫SQL語句,直接調(diào)用方法就可輕松實現(xiàn)CRUD操作。MongoDB是本系統(tǒng)中的數(shù)據(jù)存儲核心,所有爬取的數(shù)據(jù)都存放在這個數(shù)據(jù)庫中。將爬蟲爬取到的數(shù)據(jù)存入到數(shù)據(jù)庫后,將MongoDB數(shù)據(jù)庫連接到網(wǎng)頁頁面,根據(jù)用戶的輸入需求在頁面上顯示出用戶查找的機票信息,同時用戶可以使用機票的篩選、機票預(yù)訂等功能[3]。
系統(tǒng)劃分為網(wǎng)頁分析與數(shù)據(jù)提取、多線程爬蟲的實現(xiàn)、數(shù)據(jù)庫存儲、網(wǎng)頁實現(xiàn)四個模塊。其中,網(wǎng)頁分析與數(shù)據(jù)提取完成的功能是分析并且從網(wǎng)絡(luò)中抓取需要的信息;由于機票數(shù)據(jù)是實時更新的,進(jìn)而會使用分布式爬取以及定時更新,需要實現(xiàn)多線程爬蟲;從網(wǎng)絡(luò)上抓取到我們需要的機票數(shù)據(jù)節(jié)后,需要將數(shù)據(jù)進(jìn)行存儲,以方便用戶在填入需要查詢的機票信息時,系統(tǒng)可以從數(shù)據(jù)庫調(diào)度信息反饋給用戶的需求,在系統(tǒng)中加入數(shù)據(jù)庫存儲模塊;最后,為方便用戶操作以及經(jīng)過一系列的處理后,系統(tǒng)可以向用戶反饋需要的信息,加入了網(wǎng)頁實現(xiàn)這一模塊。
通過分析,本項目需要爬的數(shù)據(jù)有航空公司、起始地、目的地、艙位信息、起飛時間、票價信息等內(nèi)容。編寫爬蟲文件:在系統(tǒng)自動生成文件時,文件中已經(jīng)設(shè)置好的爬蟲的唯一“name”,允許爬取的域名以及初始爬取頁面“start_urls”,文件中的parse方法是用來處理用來處理和抓取數(shù)據(jù)[4]。
圖1 爬蟲設(shè)計圖
圖2 Scrapy框架流程圖
首先爬蟲將需要發(fā)送請求的url(requests)經(jīng)引擎交給調(diào)度器;排序處理后,經(jīng)ScrapyEngine, DownloaderMiddlewares(有User_Agent, Proxy代理)交給Downloader;Downloader向互聯(lián)網(wǎng)發(fā)送請求,并接收下載響應(yīng)。將響應(yīng)經(jīng)ScrapyEngine,可選交給Spiders;Spiders處理response,提取數(shù)據(jù)并將數(shù)據(jù)經(jīng)ScrapyEngine交給ItemPipeline保存;提取url重新經(jīng)ScrapyEngine交給Scheduler進(jìn)行下一個循環(huán),直到無Url請求程序停止結(jié)束[5]。
為了使機票信息能夠展現(xiàn)給用戶,將爬取到的數(shù)據(jù)內(nèi)容全部存入MongoDB數(shù)據(jù)庫中。使用pymongo第三方包,完成MongoDB數(shù)據(jù)庫的相關(guān)配置,即可將爬蟲爬取到的數(shù)據(jù)存入到數(shù)據(jù)庫中,MongoDB數(shù)據(jù)庫的存儲圖3所示。
圖3 MongoDB數(shù)據(jù)庫存儲
分布式采用主從結(jié)構(gòu)設(shè)置一個Master服務(wù)器和多個Slave服務(wù)器,Master端管理Redis數(shù)據(jù)庫和分發(fā)下載任務(wù),Slave部署Scrapy爬蟲提取網(wǎng)頁和解析提取數(shù)據(jù),最后將解析的數(shù)據(jù)存儲在同一個MongoDB據(jù)庫中,分布式爬蟲架構(gòu)圖4所示。
圖4 分布式爬蟲構(gòu)架圖
應(yīng)用Redis數(shù)據(jù)庫實現(xiàn)分布式抓取,基本思想是Scrapy爬蟲獲取的到的detail_request的urls都放到Redis Queue中,所有爬蟲也都從指定的Redis Queue中獲取requests,Scrapy-Redis組件中默認(rèn)使用SpiderPriorityQueue來確定url的先后次序,這是由sorted set實現(xiàn)的一種非FIFO、LIFO方式。因此,待爬隊列的共享是爬蟲可以部署在其他服務(wù)器上完成同一個爬取任務(wù)的一個關(guān)鍵點。此外,在本文中,為了解決Scrapy單機局限的問題,Scrapy將結(jié)合Scrapy-Redis組件進(jìn)行開發(fā),Scrapy-Redis總體思路就是這個工程通過重寫Scrapy框架中的scheduler和spider類,實現(xiàn)了調(diào)度、Spider啟動和Redis的交互。實現(xiàn)新的dupefilter和queue類,達(dá)到了判重和調(diào)度容器和redis的交互,因為每個主機上的爬蟲進(jìn)程都訪問同一個Redis數(shù)據(jù)庫,所以調(diào)度和判重都統(tǒng)一進(jìn)行統(tǒng)一管理,達(dá)到了分布式爬蟲的目的。
分布式爬蟲問題簡言之就是多臺機器多個 Spider 對多個 url 的同時處理問題,怎樣schedule 這些 url,怎樣匯總 spider 抓取的數(shù)據(jù)。思路就是把 url 存在某個地方,共享給所有的機器,總的調(diào)度器來分配請求,判斷 Spider 有沒有閑置,閑置了就繼續(xù)給它任務(wù),直到所有的 url 都爬完,這種方法解決了去重問題,也能提高性能,Scrapy-Redis 就實現(xiàn)了這樣一個完整框架,總的來說,這更適合廣度優(yōu)先的爬取。結(jié)合web和數(shù)據(jù)庫知識,建立網(wǎng)頁和數(shù)據(jù)庫,為用戶一套提供完整的實時性高的分布式爬蟲系統(tǒng)[6]。
以驢媽媽旅游網(wǎng)為例,該系統(tǒng)需要獲取到相關(guān)的機票數(shù)據(jù)有:航空公司、航班號、起飛降落時間、航站樓信息、票價等。接下來,對需要獲取到的機票數(shù)據(jù)進(jìn)行分析,使用Splash渲染技術(shù),當(dāng)頁面加載完成時需要的機票數(shù)據(jù)可以被加載出來。下一步,使用XPath提取頁面的信息,以航空公司名稱為例在Chrome瀏覽器使用XPath進(jìn)行初步提取,如圖6所示,可以提取到航空公司的信息。依次,使用Splash渲染技術(shù)和XPath提取全部需要的機票相關(guān)的數(shù)據(jù)內(nèi)容。
圖6 xpath提取數(shù)據(jù)圖
頁面分析與數(shù)據(jù)提取完成以后,將需要提取的數(shù)據(jù)寫入項目的items.py文件,完成settings文件中相關(guān)的配置以及完成項目中數(shù)據(jù)提取的爬蟲文件。項目已初步完成,運行該爬蟲查看爬取的結(jié)果,如圖7所示。但是由于機票數(shù)據(jù)是實時更新的,進(jìn)而會使用分布式爬蟲以及定時更新,將用戶的需求加入URL隊列進(jìn)行爬取,并且使用Linux下的crontab命令完成定時爬取數(shù)據(jù)。
為了使機票信息能夠展現(xiàn)給用戶,將爬取到的數(shù)據(jù)內(nèi)容全部存入MongoDB數(shù)據(jù)庫中。完成爬蟲爬取以后,將爬取到的數(shù)據(jù)存入到數(shù)據(jù)庫中。在MongoDB數(shù)據(jù)庫中,存入的數(shù)據(jù)如圖8所示。
圖7 部分爬取數(shù)據(jù)圖
圖8 MongoDB數(shù)據(jù)庫存儲圖
數(shù)據(jù)存入數(shù)據(jù)庫后,要將數(shù)據(jù)通過網(wǎng)頁的形式展現(xiàn)給使用方。將MongoDB數(shù)據(jù)庫連接到網(wǎng)頁頁面,根據(jù)用戶的輸入需求在頁面上顯示出用戶查找的機票信息以及訂該票的網(wǎng)站,同時用戶可以使用機票的篩選、跳轉(zhuǎn)預(yù)訂機票網(wǎng)站等功能。
本次面向民航網(wǎng)站的爬蟲系統(tǒng)的設(shè)計與實現(xiàn)中通過Python語言+Scrapy框架、Splash渲染、MongoDB數(shù)據(jù)庫和Web技術(shù)等實現(xiàn)了分布式爬蟲?;灸軌?qū)崿F(xiàn)對當(dāng)前折扣機票等信息的整理,為旅客提供更為直觀、有效的購票信息閱覽體驗。
[1]劉碩.精通Scrapy網(wǎng)絡(luò)爬蟲[M].清華大學(xué)出版社,2018.
[2]https://www.jianshu.com/p/4052926bc12c.
[3]李典桐.用于機票預(yù)訂的垂直搜索引擎的設(shè)計與實現(xiàn)[D].云南大學(xué),2015.
[4]李琳.基于Python的網(wǎng)絡(luò)爬蟲系統(tǒng)的設(shè)計與實現(xiàn)[J].信息通信,2017,(09):26-27.
[5]王芳,張睿,宮海瑞.基于Scrapy框架的分布式爬蟲設(shè)計與實現(xiàn)[J].信息技術(shù),2019(03):96-10.
[6]華云彬,匡芳君.基于Scrapy框架的分布式網(wǎng)絡(luò)爬蟲的研究與實現(xiàn)[J].智能計算機與應(yīng)用,2018,8(05):46-50.
面向民航售票網(wǎng)站的爬蟲系統(tǒng)設(shè)計與實現(xiàn)(編號:IECAUC2018015)。