趙鵬 蘇楠 于慧霞
關鍵詞:Scrapy;高性能;網(wǎng)站狀態(tài);批量采集
一、引言
目前網(wǎng)絡中的服務多以7×24 小時的方式進行不間斷工作,由于在網(wǎng)站建設中主要側重點放在了功能的實現(xiàn)上[1],往往忽略了網(wǎng)絡安全問題,導致網(wǎng)站在運營過程中對各類網(wǎng)絡攻擊行為的防護較差。在日常監(jiān)測過程中,需要實時掌握的系統(tǒng)狀態(tài)信息包括但不限于網(wǎng)站是否可用、域名解析是否正常、網(wǎng)頁內容是否被篡改、掛馬等方面。在管理較少的網(wǎng)站時,尚可采用人工的方式進行手動監(jiān)測,而當網(wǎng)站或者網(wǎng)頁數(shù)量數(shù)以千計時,如何能在短時間內及時準確地批量采集網(wǎng)站狀態(tài)信息是一個亟須解決的問題。
二、相關技術介紹
(一)Scrapy
Scrapy 是一個用Python 編寫的自由且開源的網(wǎng)絡爬蟲框架。其設計初衷是用于爬取網(wǎng)絡[2],但也可用作爬取API 數(shù)據(jù)的網(wǎng)絡爬蟲。該框架目前由Scrapinghub公司維護。Scrapy 項目圍繞“蜘蛛”(Spiders)構建,Spider 是提供一套指令的自包含的爬網(wǎng)程序。允許開發(fā)者重用代碼將便于構建和拓展大型的爬蟲項目[3]。
1.Twisted
Twisted 是用Python 實現(xiàn)的基于事件驅動的網(wǎng)絡引擎框架,Twisted 支持許多常見的傳輸及應用層協(xié)議[5],包括TCP、UDP、SSL/TLS、HTTP、IMAP、SSH、IRC及FTP。就像Python 一樣,Twisted 也具有“內置電池”(Batteries-included)的特點。Twisted 對于其支持的所有協(xié)議都帶有客戶端和服務器實現(xiàn),同時附帶有基于命令行的工具,使得配置和部署產(chǎn)品級的Twisted 應用變得非常方便[6]。
2.Splash
Splash 是一個JavaScript 渲染服務,同時也是一個帶有HTTP API 的輕量級Web 瀏覽器,使用Twisted 和QT5 在Python3 中實現(xiàn)。QT Reactor 用于使服務完全異步,從而允許通過QT 主循環(huán)利用Webkit 提高并發(fā)性。Splash 的主要功能有:并行處理多個網(wǎng)頁;獲取HTML結果和/ 或截圖;關閉圖像或使用Adblock Plus 規(guī)則來加快渲染速度;在頁面上下文中執(zhí)行自定義JavaScript;編寫Lua 瀏覽腳本; 在Splash-Jupyter 筆記本中開發(fā)Splash Lua 腳本;獲取 HAR 格式的詳細渲染信息。
三、系統(tǒng)功能概述
本文設計并實現(xiàn)的高性能批量網(wǎng)站狀態(tài)信息采集系統(tǒng)基于Scrapy 框架實現(xiàn)。在該框架基礎上自身結合自身需求設計了數(shù)據(jù)預處理、網(wǎng)站可用性采集、域名解析和網(wǎng)站首頁信息采集、數(shù)據(jù)持久化存儲共五個功能模塊。
(一)數(shù)據(jù)預處理
為了避免因為待采集的網(wǎng)站URL 不規(guī)范引起的請求錯誤,需要對待采集網(wǎng)站域名進行檢查、清洗及規(guī)整工作。具體功能包括但不限于處理待爬取網(wǎng)站列表中有些URL 沒有協(xié)議頭、一條記錄包含多個使用分隔符分隔的多個URL 等情況。
(二)網(wǎng)站響應狀態(tài)碼采集
網(wǎng)站的響應狀態(tài)碼可以體現(xiàn)出網(wǎng)站是否正??捎?,因此可采集網(wǎng)站響應狀態(tài)碼作為網(wǎng)站是否可用的判斷依據(jù)。由于網(wǎng)站的狀態(tài)是復雜多樣的,甚至是動態(tài)變化的。因此若要得到更準確的狀態(tài)碼,必須處理那些表示網(wǎng)站狀態(tài)異常的響應狀態(tài)碼,比如301、302、400、404、501 等。同時還需要處理由于網(wǎng)絡原因引起的請求超時等異常情況。
(三)域名解析信息采集
域名解析信息包括域名、對應IP 地址、歸屬地等。這些信息是通過查詢特定的API 獲取,這也正是Scrapy框架的主要功能之一。
(四)網(wǎng)站首頁信息采集
網(wǎng)站首頁信息具體包括網(wǎng)站標題、網(wǎng)站首頁文本和全屏截圖三類信息。由于目前大量網(wǎng)站都采取了動態(tài)網(wǎng)頁的設計模式,使用Scrapy 直接采集無法獲取最終的網(wǎng)站頁面狀態(tài)。因此本模塊使用Scrapy-splash 插件與Splash 服務器相配合,由Scrapy-splash 負責發(fā)起請求,Splash 負責渲染網(wǎng)頁并將渲染后的完整網(wǎng)頁返回給Scrapy。
(五)數(shù)據(jù)持久化存儲
由于Scrapy 最終解析出的數(shù)據(jù)以字典形式呈現(xiàn),而MongoDB 的操作接口均是以字典作為參數(shù),再借助Scrapy 自身提供的管道中間件無需編寫SQL 語句就可以完成數(shù)據(jù)的存儲工作,更加簡潔高效。
四、系統(tǒng)功能架構設計
系統(tǒng)功能架構如圖1 所示。
(一)系統(tǒng)功能實現(xiàn)
1. 數(shù)據(jù)預處理
BaseSpider 模塊負責待采集網(wǎng)站列表的清洗及規(guī)整工作,可以根據(jù)實際需求動態(tài)添加處理邏輯。本文主要實現(xiàn)了兩類清洗工作:一是對網(wǎng)站URL 的檢查和規(guī)整,二是對一個網(wǎng)站包含多個URL 時進行拆分和填充形成多條記錄。關鍵實現(xiàn)代碼如下:
For domain in [domain.strip().replace(‘ ‘, ‘) for domain in line.split(‘;) if domain]:
L i n e . u p d a t e ( { ‘ i d x : s e l f . g e t _ i d x ( ) , d o m a i n :domain,sk_ip: self.get_ip(domain)})
2. 網(wǎng)站響應狀態(tài)采集
HttpCodeSpider 模塊通過Scrapy.ScrapyRequest 發(fā)起Get 請求后,正常狀態(tài)下ScrapyResponse 中Status 即可作為網(wǎng)站響應狀態(tài)信息。但當網(wǎng)站狀態(tài)異常時網(wǎng)站響應狀態(tài)信息需從異常捕獲函數(shù)中收集。關鍵代碼實現(xiàn)如下所示:
Def errback(self, failure):
Cb_kwargs = failure.request.cb_kwargs
I t e m = I n s p e c t o r I t e m ( { ‘ d o m a i n : c b _kwargs[‘domain],idx: cb_kwargs[‘idx],})
Try:
Response = failure.value.response
Item.update({‘status: response.status,})
Except AttributeError:
Item.update({‘status: 700,title: failure.value})
Yield item
3. 域名解析信息采集
ApiSpider 模塊采集的數(shù)據(jù)需要通過第三方的查詢API 獲取,該API 返回JSON 格式的數(shù)據(jù)結果。發(fā)起請求時需在請求頭中指定API code 作為認證標識,在處理返回的數(shù)據(jù)時需要記錄查詢成功和失敗的數(shù)據(jù)。具體實現(xiàn)如下:
If api_ret.setdefault(‘a(chǎn)pi_msg).startswith(‘success):
Wanted_vals = [api_data.setdefault(key) for key in wanted_keys]
Api_ret.update(dict(zip(wanted_keys, wanted_vals)))
Yield InspectorItem(api_ret)
else:
Yield InspectorItem(api_ret)
4. 網(wǎng)站首頁信息采集
當目標網(wǎng)站為動態(tài)網(wǎng)站時, 普通的Scrapy.ScrapyRequest 無法獲取準確的網(wǎng)站首頁信息,SplashSpider 統(tǒng)一借助Scrapy-Splash 的SplashRequest 接口向Splash 服務器發(fā)起請求。由Splash 完成目標網(wǎng)站的渲染并返回渲染后的網(wǎng)站首頁Html 和截圖信息。由于需要獲取網(wǎng)站首頁的全屏截圖,因此需要在發(fā)起請求時指定Render_all 參數(shù)的值為1。
5. 數(shù)據(jù)持久化存儲
DBhelper 模塊存儲到數(shù)據(jù)庫中的字段信息如表1所示。
五、數(shù)據(jù)采集結果
本次測試中采集的網(wǎng)站數(shù)量為7400 個。其中網(wǎng)站響應狀態(tài)碼為200 的共計4892 個,即以最為耗時的網(wǎng)站首頁信息采集模塊為例,對網(wǎng)站狀態(tài)該模塊從啟動到最終結束共耗時5603 秒。累計采集了4892 個的網(wǎng)站首頁標題、首頁文本以及首頁全屏截圖。
六、結束語
不同于一般針對某個網(wǎng)站進行深度的數(shù)據(jù)采集,本文所提出的采集系統(tǒng)主要是解決如何批量采集網(wǎng)站狀態(tài)信息的問題。其難點在于待監(jiān)測的網(wǎng)站數(shù)量龐大、采集的數(shù)據(jù)來源較為分散、動態(tài)網(wǎng)站的數(shù)據(jù)無法直接通過一次網(wǎng)絡請求就完成采集。本文在Scrapy 的基礎上結合Scrapy-splash、Splash 等技術手段實現(xiàn)對多個網(wǎng)站狀態(tài)信息的批量采集和動態(tài)網(wǎng)站首頁信息的精確采集,能夠為后續(xù)網(wǎng)站的日常監(jiān)測和狀態(tài)分析提供有效支撐。
作者單位:趙鵬 蘇楠 于慧霞 國家計算機網(wǎng)絡與信息安全管理中心寧夏分中心