楊宇
(貴州電子信息職業技術學院,貴州 凱里 556000)
隨著互聯網大數據技術的不斷發展[1],數據成為最寶貴的資源,網絡數據采集技術成為熱門的研究領域之一。Python 具有易于配置、處理字符靈活等特性,且具有Urlib、Requests、Selenium 等豐富的網絡爬蟲模塊[2],但這些模塊在進行網絡數據爬蟲時,性能差、耗時長、效率低、易阻塞。Scrapy框架是基于Python語言編寫的網絡爬蟲框架[3],具有效率高、非阻塞、異步爬取等特性,能夠有效解決Python內置網絡爬蟲模塊的不足。公交是市民日常出現最為重要的交通數據,對公交數據進行采集分析具有重要的意義。本文采用Scrapy 爬蟲技術,結合Kelltle 數據預處理技術[4]、Flask+Echarts數據可視化技術[5],搭建一種數據采集與分析平臺。
該系統整個平臺設計如圖1所示。

圖1 平臺設計框圖
該平臺主要由數據采集、數據預處理、數據存儲及數據可視化四個子模塊構成。數據采集通過Scrapy框架實現,采集到的數據存儲到CSV文件中;數據預處理由Kelttle工具實現,網絡爬蟲模塊爬取到的數據需要經過數據預處理模塊進行預處理;數據預處理完成以后,將結果保存到MySQL數據庫中;最后,通過Flask+Echarts框架搭建數據可視化模塊,實現分析結果的可視化。
Scrapy是Python開發的一個快速屏幕抓取和Web抓取框架,用于抓取Web 站點并從此頁面中提取結構化數據,它是Python爬蟲技術中最為常用的一個框架[6],其構架如圖2所示。

圖2 scrapy構架圖
有關Scrapy的各個部分的組件的詳細說明如下:
(1)引擎(Scrapy Engine):負責其他部件的通信信號和數據傳遞。
(2)調度器(Scheduler):將Request請求排列入隊。
(3)下載器(Downloader):用于高速下載網絡資源。
(4)蜘蛛(Spiders):解析Response 數據,獲取Item 中定義的字段數據。
(5)項目管道(Item Pipeline):用于處理Spider中獲取的數據。
(6)下載中間件:主要用來處理Scrapy引擎與下載器之間的請求及響應。
啟動數據采集后,引擎會打開一個網站,找到處理該網站所用的Spider,并向該Spider 請求第一個爬取的URL。引擎從Spider中獲取到第一個爬取URL,并通過調度器以Request形式進行任務調度,隨后引擎會向調度器請求下一個需要爬取的URL,調度器將下一個要爬取的URL給引擎,引擎通過下載中間件將URL 發送給下載器,下載器開始啟動頁面下載,下載完成后即可生成Response 對象,然后通過下載中間件返回給引擎,引擎收到Response對象后,通過爬蟲中間件將其發送給Spider進行處理。Spider從Response對象中提取Item數據對象及新的Request請求,一同發送給引擎,引擎將Item 數據對象給項目管道,對數據進行持久化操作,將新的Request請求交給調度器,進行新一輪的下載調度。通過多組件相互協作,不同組件負責不同工種,實現組件之間異步處理,從而有效利用網絡帶寬,提高數據爬取及處理的效率。
設計流程:
新建Scrapy項目工程,在工程目錄結構中,setting.py負責爬蟲相關配置,其中爬蟲名稱配置如下:
BOT_NAME='beijingbus'
請求頭配置如下:


管道配置如下:

數據庫配置如下:
DB_HOST='localhost'
DB_USER='root'
DB_PWD='12101210'
DB='beijingbus'
DB_CHARSET='utf8'
管道配置如下:

其中,數字代表優先級,數字越小,優先級越高。
items.py負責定義需要爬取的字段域等信,如下:
bus_name=scrapy.Field()#公交線路名
bus_type=scrapy.Field()#工具類型
bus_time=scrapy.Field()#運行票價
bus_ticket=scrapy.Field()#公交票價
bus_company=scrapy.Field()#公司名
wang_info=scrapy.Field()#往車站信息
fan_info=scrapy.Field()#返車站信息
Spider包下的bei_bus.py負責數據爬取與響應數據xpath解析,主要在BeiBusSpider類中實現,在該類中,函數start_requests 主要實現以數字1-9,以字母:BCDFGHKLMPSTXYZ開頭的url的拼接及請求發送,核心代碼如下:
url'{url}/list{page}'.format(url=self.start_urls,page=(page+1))#URL拼接
yield Request(url,callback=self.parse_index1)#請求發送
函數parse_index1 負責提取詳細被包含公交線路url,并于start_url 進行拼接,得到完整的詳細公交線路url,核心代碼如下:
beijingbus = response.xpath('//div[@class="list clearfix"]//a/@href').extract()#通過xpath 提取每一班公交子url,再將其和start_url拼接,然后將完整的url請求發送到下一級處理函數parse_detail2,該函數主要通過xpath 實現詳情頁數據提取。任意舉例3個屬性,核心代碼如下:
bus_name = response.xpath('//div[@class="info"]/h1//text()').
extract_first() #公交名稱
bus_time = response.xpath('//div[@class="info"]/ul/li[1]//text()').extract_first() #運行時間
bus_type=response.xpath('//div[@class="info"]/ul/li[2]//text()').extract_first() #線路路線
Spider 包下的run.py 負責整個爬蟲工程運行,實現代碼如下:
from scrapy import cmdline
cmdline.execute('scrapy craw l bei_bus'.split()),其 中,bei_bus為爬蟲名。
pipelines.py 負責接收spider 爬取的數據,并將數據進行持久化等操作,主要是將爬取到的數據寫入csv文件中,主要實現代碼如下:

其中函數__init__負責初始化工作,主要是打開需要寫入數據的csv文件及定義寫入規則,函數process_item主要實現數據的封裝與寫入csv文件。
綜上,整個公交數據爬取詳細流程如圖3所示。

圖3 數據爬取流程圖
數據預處理采用Kettle工具實現,Kettle是一款比較實用的ETL 工具,通過圖形化描述數據清洗的整個流程,其在數據清洗時,主要由轉換負責完成,它是ETL 解決方案中重要的組成部分之一,其主要用于數據的抽取、轉換以及加載等操作,本質是一組圖形化的數據轉換配置的邏輯結構。一個轉換包括一個或多個步驟,例如讀取文件、過濾輸出行、數據清洗或將數據加載到數據庫等步驟。轉換中的步驟是通過跳來連接的,跳定義了一個單向通道,允許數據從一個步驟向另一個步驟流動。在Kettle中,數據的單位是行,數據流就是數據行從一個步驟到另一個步驟的移動[7]。數據清洗的主要流程如圖4所示。

圖4 數據清洗流程
在進行數據清洗前,需要先通過Kettle 工具創建一個轉換,導入需要處理的數據,重點對重復值及缺失值進行處理,最終將處理后的結果導出到MySQL數據庫中進行存儲。
數據存儲采用MySQL 數據庫實現,爬蟲過程中的數據持久化即是將數據寫入MySQL 數據庫,數據庫表單結構如表1所示。

表1 數據庫表單結構
數據可視化采用Flask+Echarts技術框架進行設計,Flask是Python Web 開發的微框架,在Flask 框架的基礎上再采用SQLAlchemy 技術編寫數據庫映射模型,完成數據庫表結構映射模型。Echarts 通過Javascript 發揮強大作用,實現數據的動態可視化。數據可視化設計流程如圖5所示。

圖5 數據可視化設計流程
整個實驗的環境說明如表2所示。

表2 實驗環境說明
數據預處理試驗結果如圖6及表3所示。
從圖6及表3得出輸入的公交車數據為1089條,過濾、去重后得到的公交車數據為689條,清洗掉不滿足條件數據為400條。

圖6 數據預處理轉換圖

表3 數據預處理過程
公交線路類型可視化如圖7所示。
從圖7分析得知:北京公交線路類型分為市區普線、郊區普線及通勤普線三類,市區普線占比高達70.97%。

圖7 公交線路類型占比
公交的可視化如圖8所示。

圖8 公交往返線路
從圖8得知:北京往返線路多,交叉站點多,從而給乘客提供較多的乘坐方案。
本文通過Scrapy 數據采集、Kettle 數據清洗、MySQL 數據存儲及Flask 整合Echarts 數據可視化,提供一種數據采集與分析平臺的詳細設計思路,并以北京公交為例進行數據測試。測試結果表明:系統穩定可靠、操作簡單、實時性強,具有一定的社會意義及參考價值。