◆郭慧珍 劉雨澤 梁燁文 王 哲 宋佳音
面向民航售票網(wǎng)站的實(shí)時(shí)爬蟲(chóng)系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)
◆郭慧珍 劉雨澤 梁燁文 王 哲 宋佳音
(中國(guó)民航大學(xué)計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院 天津 300300)
近年來(lái),隨著互聯(lián)網(wǎng)、大數(shù)據(jù)、信息化以及電子商務(wù)等計(jì)算機(jī)技術(shù)相關(guān)領(lǐng)域日新月異的發(fā)展,互聯(lián)網(wǎng)上存在著大量的可利用的有效信息。隨著這些技術(shù)的發(fā)展,爬蟲(chóng)技術(shù)也得到了廣泛的應(yīng)用而快速發(fā)展,實(shí)現(xiàn)了有效信息快速高效的采集和整合,本文介紹了面向民航售票網(wǎng)站的實(shí)時(shí)爬蟲(chóng)系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn),供讀者參考。
網(wǎng)絡(luò)爬蟲(chóng);Scrapy框架;MongoDB數(shù)據(jù)庫(kù)
隨著我國(guó)綜合國(guó)力和人們生活水平的提高,飛機(jī)已經(jīng)成為人們重要的出行方式之一。但是不同于傳統(tǒng)的鐵路運(yùn)輸方式,很多時(shí)候航空公司會(huì)提供價(jià)格較低的機(jī)票,以促進(jìn)銷售額或?yàn)槁每吞峁┬詢r(jià)比更高的服務(wù)。但是大多數(shù)時(shí)候,機(jī)票信息紛繁復(fù)雜,旅客無(wú)法準(zhǔn)確及時(shí)獲取打折機(jī)票的信息。顯然,如何及時(shí)有效的整理當(dāng)前折扣機(jī)票,為旅客提供更為直觀、有效的購(gòu)票信息閱覽體驗(yàn)成為值得探索的話題。因此,實(shí)現(xiàn)信息獲取和整合是我們要完成的主要任務(wù)。網(wǎng)絡(luò)爬蟲(chóng)是一種按照一定的規(guī)則,自動(dòng)地抓取萬(wàn)維網(wǎng)信息的程序或者腳本,它們被廣泛用于互聯(lián)網(wǎng)搜索引擎或其他類似網(wǎng)站,可以自動(dòng)采集所有其能夠訪問(wèn)到的頁(yè)面內(nèi)容,以獲取或更新這些網(wǎng)站的內(nèi)容和檢索方式。
為了提高系統(tǒng)的效率,同時(shí)對(duì)多個(gè)任務(wù)加以控制,在同一時(shí)間需要完成多項(xiàng)任務(wù),本系統(tǒng)中使用Scrapy框架來(lái)實(shí)現(xiàn)多線程。Scrapy是用純Python實(shí)現(xiàn)一個(gè)為了爬取網(wǎng)站數(shù)據(jù)、提取結(jié)構(gòu)性數(shù)據(jù)而編寫(xiě)的應(yīng)用框架。Scrapy使用了 Twisted異步網(wǎng)絡(luò)框架來(lái)處理網(wǎng)絡(luò)通訊,可以加快我們的下載速度,不用自己去實(shí)現(xiàn)異步框架,并且包含了各種中間件接口,可以靈活完成各種需求[1]。
Splash是Scrapy官方推薦的JavaScript渲染,它是使用WebKit開(kāi)發(fā)的輕量級(jí)無(wú)界面瀏覽器,提供基于HTTP接口的JavaScript渲染服務(wù)。XPath即為XML路徑語(yǔ)言(XML Path Language),它是一種用來(lái)確定XML文檔中某部分位置的語(yǔ)言。本系統(tǒng)中,依次,使用Splash渲染技術(shù)和xpath提取全部需要的機(jī)票相關(guān)的數(shù)據(jù)內(nèi)容。使用Splash渲染技術(shù),對(duì)需要獲取到的票價(jià)等機(jī)票數(shù)據(jù)進(jìn)行分析,當(dāng)頁(yè)面加載完成時(shí)需要的機(jī)票數(shù)據(jù)可以被加載出來(lái)。下一步,使用XPath提取頁(yè)面的信息,以航空公司名稱為例在谷歌瀏覽器使用XPath進(jìn)行初步提取[2]。
MongoDB是NoSQL(非關(guān)系型數(shù)據(jù)庫(kù))中的一類文檔型數(shù)據(jù)庫(kù),其數(shù)據(jù)存儲(chǔ)方式靈活。MongoDB也很好地實(shí)現(xiàn)了面向?qū)ο蟮乃枷耄贛ongoDB中,每一條記錄都是一個(gè)Document對(duì)象。MongoDB最大的優(yōu)勢(shì)在于所有的數(shù)據(jù)持久操作都無(wú)須開(kāi)發(fā)人員手動(dòng)編寫(xiě)SQL語(yǔ)句,直接調(diào)用方法就可輕松實(shí)現(xiàn)CRUD操作。MongoDB是本系統(tǒng)中的數(shù)據(jù)存儲(chǔ)核心,所有爬取的數(shù)據(jù)都存放在這個(gè)數(shù)據(jù)庫(kù)中。將爬蟲(chóng)爬取到的數(shù)據(jù)存入到數(shù)據(jù)庫(kù)后,將MongoDB數(shù)據(jù)庫(kù)連接到網(wǎng)頁(yè)頁(yè)面,根據(jù)用戶的輸入需求在頁(yè)面上顯示出用戶查找的機(jī)票信息,同時(shí)用戶可以使用機(jī)票的篩選、機(jī)票預(yù)訂等功能[3]。
系統(tǒng)劃分為網(wǎng)頁(yè)分析與數(shù)據(jù)提取、多線程爬蟲(chóng)的實(shí)現(xiàn)、數(shù)據(jù)庫(kù)存儲(chǔ)、網(wǎng)頁(yè)實(shí)現(xiàn)四個(gè)模塊。其中,網(wǎng)頁(yè)分析與數(shù)據(jù)提取完成的功能是分析并且從網(wǎng)絡(luò)中抓取需要的信息;由于機(jī)票數(shù)據(jù)是實(shí)時(shí)更新的,進(jìn)而會(huì)使用分布式爬取以及定時(shí)更新,需要實(shí)現(xiàn)多線程爬蟲(chóng);從網(wǎng)絡(luò)上抓取到我們需要的機(jī)票數(shù)據(jù)節(jié)后,需要將數(shù)據(jù)進(jìn)行存儲(chǔ),以方便用戶在填入需要查詢的機(jī)票信息時(shí),系統(tǒng)可以從數(shù)據(jù)庫(kù)調(diào)度信息反饋給用戶的需求,在系統(tǒng)中加入數(shù)據(jù)庫(kù)存儲(chǔ)模塊;最后,為方便用戶操作以及經(jīng)過(guò)一系列的處理后,系統(tǒng)可以向用戶反饋需要的信息,加入了網(wǎng)頁(yè)實(shí)現(xiàn)這一模塊。
通過(guò)分析,本項(xiàng)目需要爬的數(shù)據(jù)有航空公司、起始地、目的地、艙位信息、起飛時(shí)間、票價(jià)信息等內(nèi)容。編寫(xiě)爬蟲(chóng)文件:在系統(tǒng)自動(dòng)生成文件時(shí),文件中已經(jīng)設(shè)置好的爬蟲(chóng)的唯一“name”,允許爬取的域名以及初始爬取頁(yè)面“start_urls”,文件中的parse方法是用來(lái)處理用來(lái)處理和抓取數(shù)據(jù)[4]。

圖1 爬蟲(chóng)設(shè)計(jì)圖

圖2 Scrapy框架流程圖
首先爬蟲(chóng)將需要發(fā)送請(qǐng)求的url(requests)經(jīng)引擎交給調(diào)度器;排序處理后,經(jīng)ScrapyEngine, DownloaderMiddlewares(有User_Agent, Proxy代理)交給Downloader;Downloader向互聯(lián)網(wǎng)發(fā)送請(qǐng)求,并接收下載響應(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)行下一個(gè)循環(huán),直到無(wú)Url請(qǐng)求程序停止結(jié)束[5]。
為了使機(jī)票信息能夠展現(xiàn)給用戶,將爬取到的數(shù)據(jù)內(nèi)容全部存入MongoDB數(shù)據(jù)庫(kù)中。使用pymongo第三方包,完成MongoDB數(shù)據(jù)庫(kù)的相關(guān)配置,即可將爬蟲(chóng)爬取到的數(shù)據(jù)存入到數(shù)據(jù)庫(kù)中,MongoDB數(shù)據(jù)庫(kù)的存儲(chǔ)圖3所示。

圖3 MongoDB數(shù)據(jù)庫(kù)存儲(chǔ)
分布式采用主從結(jié)構(gòu)設(shè)置一個(gè)Master服務(wù)器和多個(gè)Slave服務(wù)器,Master端管理Redis數(shù)據(jù)庫(kù)和分發(fā)下載任務(wù),Slave部署Scrapy爬蟲(chóng)提取網(wǎng)頁(yè)和解析提取數(shù)據(jù),最后將解析的數(shù)據(jù)存儲(chǔ)在同一個(gè)MongoDB據(jù)庫(kù)中,分布式爬蟲(chóng)架構(gòu)圖4所示。

圖4 分布式爬蟲(chóng)構(gòu)架圖
應(yīng)用Redis數(shù)據(jù)庫(kù)實(shí)現(xiàn)分布式抓取,基本思想是Scrapy爬蟲(chóng)獲取的到的detail_request的urls都放到Redis Queue中,所有爬蟲(chóng)也都從指定的Redis Queue中獲取requests,Scrapy-Redis組件中默認(rèn)使用SpiderPriorityQueue來(lái)確定url的先后次序,這是由sorted set實(shí)現(xiàn)的一種非FIFO、LIFO方式。因此,待爬隊(duì)列的共享是爬蟲(chóng)可以部署在其他服務(wù)器上完成同一個(gè)爬取任務(wù)的一個(gè)關(guān)鍵點(diǎn)。此外,在本文中,為了解決Scrapy單機(jī)局限的問(wèn)題,Scrapy將結(jié)合Scrapy-Redis組件進(jìn)行開(kāi)發(fā),Scrapy-Redis總體思路就是這個(gè)工程通過(guò)重寫(xiě)Scrapy框架中的scheduler和spider類,實(shí)現(xiàn)了調(diào)度、Spider啟動(dòng)和Redis的交互。實(shí)現(xiàn)新的dupefilter和queue類,達(dá)到了判重和調(diào)度容器和redis的交互,因?yàn)槊總€(gè)主機(jī)上的爬蟲(chóng)進(jìn)程都訪問(wèn)同一個(gè)Redis數(shù)據(jù)庫(kù),所以調(diào)度和判重都統(tǒng)一進(jìn)行統(tǒng)一管理,達(dá)到了分布式爬蟲(chóng)的目的。
分布式爬蟲(chóng)問(wèn)題簡(jiǎn)言之就是多臺(tái)機(jī)器多個(gè) Spider 對(duì)多個(gè) url 的同時(shí)處理問(wèn)題,怎樣schedule 這些 url,怎樣匯總 spider 抓取的數(shù)據(jù)。思路就是把 url 存在某個(gè)地方,共享給所有的機(jī)器,總的調(diào)度器來(lái)分配請(qǐng)求,判斷 Spider 有沒(méi)有閑置,閑置了就繼續(xù)給它任務(wù),直到所有的 url 都爬完,這種方法解決了去重問(wèn)題,也能提高性能,Scrapy-Redis 就實(shí)現(xiàn)了這樣一個(gè)完整框架,總的來(lái)說(shuō),這更適合廣度優(yōu)先的爬取。結(jié)合web和數(shù)據(jù)庫(kù)知識(shí),建立網(wǎng)頁(yè)和數(shù)據(jù)庫(kù),為用戶一套提供完整的實(shí)時(shí)性高的分布式爬蟲(chóng)系統(tǒng)[6]。
以驢媽媽旅游網(wǎng)為例,該系統(tǒng)需要獲取到相關(guān)的機(jī)票數(shù)據(jù)有:航空公司、航班號(hào)、起飛降落時(shí)間、航站樓信息、票價(jià)等。接下來(lái),對(duì)需要獲取到的機(jī)票數(shù)據(jù)進(jìn)行分析,使用Splash渲染技術(shù),當(dāng)頁(yè)面加載完成時(shí)需要的機(jī)票數(shù)據(jù)可以被加載出來(lái)。下一步,使用XPath提取頁(yè)面的信息,以航空公司名稱為例在Chrome瀏覽器使用XPath進(jìn)行初步提取,如圖6所示,可以提取到航空公司的信息。依次,使用Splash渲染技術(shù)和XPath提取全部需要的機(jī)票相關(guān)的數(shù)據(jù)內(nèi)容。

圖6 xpath提取數(shù)據(jù)圖
頁(yè)面分析與數(shù)據(jù)提取完成以后,將需要提取的數(shù)據(jù)寫(xiě)入項(xiàng)目的items.py文件,完成settings文件中相關(guān)的配置以及完成項(xiàng)目中數(shù)據(jù)提取的爬蟲(chóng)文件。項(xiàng)目已初步完成,運(yùn)行該爬蟲(chóng)查看爬取的結(jié)果,如圖7所示。但是由于機(jī)票數(shù)據(jù)是實(shí)時(shí)更新的,進(jìn)而會(huì)使用分布式爬蟲(chóng)以及定時(shí)更新,將用戶的需求加入U(xiǎn)RL隊(duì)列進(jìn)行爬取,并且使用Linux下的crontab命令完成定時(shí)爬取數(shù)據(jù)。
為了使機(jī)票信息能夠展現(xiàn)給用戶,將爬取到的數(shù)據(jù)內(nèi)容全部存入MongoDB數(shù)據(jù)庫(kù)中。完成爬蟲(chóng)爬取以后,將爬取到的數(shù)據(jù)存入到數(shù)據(jù)庫(kù)中。在MongoDB數(shù)據(jù)庫(kù)中,存入的數(shù)據(jù)如圖8所示。

圖7 部分爬取數(shù)據(jù)圖

圖8 MongoDB數(shù)據(jù)庫(kù)存儲(chǔ)圖
數(shù)據(jù)存入數(shù)據(jù)庫(kù)后,要將數(shù)據(jù)通過(guò)網(wǎng)頁(yè)的形式展現(xiàn)給使用方。將MongoDB數(shù)據(jù)庫(kù)連接到網(wǎng)頁(yè)頁(yè)面,根據(jù)用戶的輸入需求在頁(yè)面上顯示出用戶查找的機(jī)票信息以及訂該票的網(wǎng)站,同時(shí)用戶可以使用機(jī)票的篩選、跳轉(zhuǎn)預(yù)訂機(jī)票網(wǎng)站等功能。
本次面向民航網(wǎng)站的爬蟲(chóng)系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)中通過(guò)Python語(yǔ)言+Scrapy框架、Splash渲染、MongoDB數(shù)據(jù)庫(kù)和Web技術(shù)等實(shí)現(xiàn)了分布式爬蟲(chóng)。基本能夠?qū)崿F(xiàn)對(duì)當(dāng)前折扣機(jī)票等信息的整理,為旅客提供更為直觀、有效的購(gòu)票信息閱覽體驗(yàn)。
[1]劉碩.精通Scrapy網(wǎng)絡(luò)爬蟲(chóng)[M].清華大學(xué)出版社,2018.
[2]https://www.jianshu.com/p/4052926bc12c.
[3]李典桐.用于機(jī)票預(yù)訂的垂直搜索引擎的設(shè)計(jì)與實(shí)現(xiàn)[D].云南大學(xué),2015.
[4]李琳.基于Python的網(wǎng)絡(luò)爬蟲(chóng)系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[J].信息通信,2017,(09):26-27.
[5]王芳,張睿,宮海瑞.基于Scrapy框架的分布式爬蟲(chóng)設(shè)計(jì)與實(shí)現(xiàn)[J].信息技術(shù),2019(03):96-10.
[6]華云彬,匡芳君.基于Scrapy框架的分布式網(wǎng)絡(luò)爬蟲(chóng)的研究與實(shí)現(xiàn)[J].智能計(jì)算機(jī)與應(yīng)用,2018,8(05):46-50.
面向民航售票網(wǎng)站的爬蟲(chóng)系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)(編號(hào):IECAUC2018015)。