趙本本 殷旭東 王偉
摘 要作為最大的社交編程及代碼托管網站,GitHub提供了豐富的數(shù)據(jù)來源?;赑ython開源框架Scrapy設計實現(xiàn)了一個Web爬蟲,能對GitHub的資源抓取和分析,并進行了結構化處理和存儲,可為后續(xù)數(shù)據(jù)分析提供基礎。介紹了GitHub爬蟲的設計原理、算法的實現(xiàn)方式,對實驗結果進行了分析。
【關鍵詞】網絡爬蟲 數(shù)據(jù)爬取 Scrapy GitHub Python NoSQL
數(shù)據(jù)產生于各行各業(yè),在互聯(lián)網時代大數(shù)據(jù)概念提出后,人們發(fā)現(xiàn)自己手中的數(shù)據(jù)不再毫無用處,通過強大的技術手段,無形的數(shù)據(jù)可轉化為有形資產。麥肯錫公司的報告指出數(shù)據(jù)是一種生產資料,大數(shù)據(jù)是下一個創(chuàng)新、競爭、生產力提高的前沿。 世界經濟論壇的報告也認定大數(shù)據(jù)為新財富,價值堪比石油。GitHub是一個巨大的數(shù)據(jù)寶庫,吸引了大量的開發(fā)人員與研究人員入駐。2014年的《GitHub中國開發(fā)者年度報告》指出,目前 GitHub 上的注冊用戶數(shù)量已經超過1000萬。由于網站托管的開源項目眾多,訪問的流量也呈爆炸性增長。要想從數(shù)千萬程序員中快速、準確地抓取所需要的信息變得越來越困難,所以必須使用自動化工具才能較容易的抓取下來。
本文設計并實現(xiàn)了一個基于Scrapy框架的Web數(shù)據(jù)爬蟲,從GitHub抓取大量用戶數(shù)據(jù)信息,下載到本地,進行了結構化處理和存儲,為之后做數(shù)據(jù)分析提供基礎。
1 網絡爬蟲與Scrapy
所謂網絡爬蟲,就是抓取特定網站網頁的HTML數(shù)據(jù)。網絡爬蟲從一個存放URL的集合開始進行爬取,首先從隊列中獲取一個URL并下載此網頁,提取該網頁中的其它URL并放入隊列中。此過程將重復直至關閉。常見的網絡爬蟲及其爬行策略包括:
(1)廣度優(yōu)先爬蟲,一般全網搜索引擎的網絡爬蟲使用廣度優(yōu)先的爬行策略。
(2)重新爬取已有的頁面的爬蟲,目的是獲得數(shù)據(jù)的定期更新。
(3)聚焦爬蟲,也叫定向爬蟲,為很多垂直搜索引擎使用,采取特定的爬行策略來爬取特定類型的網頁。本文所研究的正是這一類型的網絡爬蟲。例如,網頁上的某個特定主題或語言、圖像、MP3文件等。
Scrapy是用Python開發(fā)的一個開源的Web爬蟲框架,可用于快速抓取Web站點并從頁面中高效提取結構化的數(shù)據(jù)。Scrapy可廣泛應用于數(shù)據(jù)挖掘、監(jiān)測和自動化測試等方面,提供了多種類型爬蟲的基類,如BaseSpider、SitemapSpider等。
2 基于Scrapy的Github數(shù)據(jù)爬蟲的設計
2.1 Scrapy原理
Scrapy是基于Twisted異步網絡庫來處理通訊,架構清晰,并且包含了各種中間件接口,可以靈活的完成各種需求。其工作原理為:首先從種子URL開始,調度器會傳給下載器進行下載,之后會交給爬蟲進行分析,根據(jù)分析結果進行不同處理。如果是需要進一步爬取的鏈接,這些鏈接會傳回調度器;如果是需要保存的數(shù)據(jù),則被送到項目管道組件進行后期處理,包括詳細分析、過濾、存儲等。此外,在數(shù)據(jù)流動的通道里還允許安裝各種中間件,進行必要的處理。
2.2 GitHub數(shù)據(jù)爬蟲
2.2.1 GitHub網頁結構與數(shù)據(jù)分析
GitHub個人主頁的主要信息可分為左右兩塊:左塊為個人基本信息,右塊為個人相關的項目。個人基本信息包括名字、郵箱、公司、頭像等,爬取時會按照編寫的爬蟲規(guī)則全部保存下來,同時右塊的項目信息也儲存在JSON文件中。格式為:
{
“_id”:
“fullname”:
“mail”:
“username”:
“organization”:
“joined”:
“starred”:
…
}。
2.2.2 數(shù)據(jù)定義
Item是保存爬取到的數(shù)據(jù)容器,使用方法和Python字典類似。根據(jù)從GitHub網站上獲取到的數(shù)據(jù)followers、fullname等對Item進行統(tǒng)一建模。從而在Item中定義相應的字段field。對應的item.py中的主要代碼為:
import scrapy
class GithubItem(scrapy.Item):
fullname = scrapy.Field()
username = scrapy.Field()
popular_repos = scrapy.Field()
…
2.2.3 編寫提取Item數(shù)據(jù)的Spider
GitHubSpider是用于GitHub網站爬取數(shù)據(jù)的類,選擇從scrapy.Spider類繼承。定義以下屬性和方法:
(1)name屬性:定義spider名字的字符串且唯一;
(2)start_urls屬性:Spider在啟動時從url列表開始進行爬取。第一個被獲取到的頁面將是其中之一,后續(xù)的URL則從初始的頁面中提??;
(3)parse:是Spider的一個方法。每個初始URL完成下載后生成的Response對象將會作為唯一的參數(shù)傳遞給該方法。該方法解析提取Item數(shù)據(jù)以及生成需要進一步處理的URL的Request對象。
Scrapy提取數(shù)據(jù)使用Selector選擇器機制,使用特定的XPath表達式來提取HTML網頁中的數(shù)據(jù)。此爬蟲提取GitHub用戶主頁中的followers數(shù)據(jù)項使用代碼:
people['followers']=response.xpath('//div[@class="vcard-stats"]/a[1]/strong[@class="vcard-stat-count"]/text()').extract();
即提取class為vcard-stats的div標簽內的第一個a標簽里的class為vcard-stat-count的strong標簽內的文本數(shù)據(jù)。
2.3 數(shù)據(jù)存儲NoSQL
網絡爬蟲系統(tǒng)爬取的數(shù)據(jù)量大,且多為半結構化或非結構化數(shù)據(jù),傳統(tǒng)的關系型數(shù)據(jù)庫并不擅長這類數(shù)據(jù)的存儲與處理。而NoSQL在大數(shù)據(jù)存取上具備關系型數(shù)據(jù)庫無法比擬的性能優(yōu)勢,因此選擇使用NoSQL數(shù)據(jù)庫存儲爬取到的數(shù)據(jù)。
2.3.1 數(shù)據(jù)存儲方式
MongoDB是一個基于分布式文件存儲的非關系型數(shù)據(jù)庫,具有靈活的數(shù)據(jù)存儲方式。MongoDB數(shù)據(jù)存儲不需要固定的表結構,也不存在連接操作。其次它是一種基于文檔的、無模式且不保證ACID的數(shù)據(jù)庫。每當抓取數(shù)據(jù)到Item項時,都會添加進一個Mongo集合。
2.3.2 設置數(shù)據(jù)庫
在settings.py文件里設置MongoDB的參數(shù):服務器SERVER、端口PORT、數(shù)據(jù)庫DB、數(shù)據(jù)庫表COLLECTION,之后指定管道后添加數(shù)據(jù)庫設置:
ITEM_PIPELINES={ 'GitHub.pipelines.MongoDBpipeline':300,}
2.3.3 連接數(shù)據(jù)庫
在pipelines.py文件中通過管道連接。首先定義一個函數(shù)去連接數(shù)據(jù)庫:
class MongoDBpipeline(object):
def __init__(self):
MongoClient(…)
def process_item(self, item, spider):
…
return item
創(chuàng)建了一個類MongoDBPipeline(),構造初始函數(shù)初始化類。process_item()函數(shù)處理被解析的數(shù)據(jù)。
2.4 反爬蟲技術的應對措施
很多網站為避免被爬蟲抓取數(shù)據(jù),使用了一定的規(guī)則和特定的機制來實現(xiàn),本爬蟲主要采取以下措施:
(1)設置download_delay,即下載器在下載同一個網站下一個頁面前需要等待時間。如果下載等待時間長,則不能滿足短時間大規(guī)模抓取的要求;而太短則大大增加了被Ban的幾率。因此在settings.py中設置:DOWNLOAD_DELAY = 2;
(2)禁止cookies,可以防止使用cookies識別爬蟲軌跡的網站察覺,在settings.py設置:COOKIES_ENABLES=False;
(3)使用user agent池,防止被服務器識別,將user agent池寫入rotate_useragent.py文件里。
2.5 爬蟲工作方式及算法
GitHub網站上網頁數(shù)以百萬記,且分布在全世界各個地方的服務器。對于GitHub這樣的網站來說,適合采取定向爬蟲策略。即從第一個URL種子開始,來收集所有的用戶信息和可以利用的用戶URL并保存起來,之后遍歷整個URL集合。
GitHub爬蟲采取寬度優(yōu)先遍歷策略,其基本思路是將新下載網頁中發(fā)現(xiàn)的鏈接直接插入待抓取URL隊列。也就是指網絡爬蟲會先抓取起始網頁中鏈接的所有網頁,然后再選擇其中的一個鏈接網頁,繼續(xù)抓取在此網頁中鏈接的所有網頁。
(1)首先由圖開始從用戶URL種子進行爬取,即用戶主頁面。然后通過爬蟲將網頁中個人信息提取出來并分別存儲到每個人新創(chuàng)建在本地的文檔中。
(2)通過判斷用戶的關注者即是否等于0而繼續(xù)循環(huán)爬行還是重新爬行,不為0時會保存每一個被關注者的鏈接到URL隊列里面,方便繼續(xù)循環(huán)。
(3)循環(huán)爬取時會保存每一個用戶的關注頁面,因為如果循環(huán)完用戶之后,還有個他的關注者URL頁面沒用到,進入關注頁面會有重新一批用戶,然后再添加入循環(huán)。
(4)關注者與被關注者難免會互相關注,所以爬取時會重復爬取,但不會重復下載信息。
爬蟲算法用偽代碼描述如下:
Begin
init
name←github
headers←{Accpet,User-Agent,..}
allowed_domains←github.com
start_url←["https://github.com/someone",]
return A
A people←Github_Item()
people←response.xpath(“//...”)
Save as TXT. call B(self,response)
B Store as followers_urls、people_urls_list
Duplicates_Removal followers_urls、people_urls_list
people_link_1←people_urls_list[0]
people_urls_list.remove(people_link_1)
call C(people_link_1)
C Count followers
IF followers≠0 THEN
followers_urls.append(url)
call A(url);
ELSE
IF followers_urls ≠ [] THEN
followers_link_1←followers_urls[0]
followers_urls.remove(followers_link_1)
call A(followers_link_1);
ELSE
people_link_1←people_urls_list[0]
people_urls_list.remove(people_link_1)
call A(people_link_1)
END IF
END IF
END
3 實驗與分析
3.1 實驗結果
對以上的爬蟲進行python代碼的編寫,啟動運行scrapy crawl github -s LOG_FILE=scrapy.log,下面是部分數(shù)據(jù)的展示。圖2展示了用戶個人信息保存在文本文件中的數(shù)據(jù),圖3為MongoDB數(shù)據(jù)庫內存儲的數(shù)據(jù),可用于統(tǒng)計分析查詢。
3.2 實驗分析
實驗環(huán)境使用一臺PC機運行爬蟲程序,并且同時運行數(shù)據(jù)存儲服務器。實驗測試中,臨時暫停發(fā)現(xiàn)共爬取了221次(有重復),保存了152人,URL隊列中還有623條個人主頁沒爬取。沒有發(fā)現(xiàn) Crawled (429)(太多請求)等警告信息。
爬取會時不時的停頓,有時出現(xiàn)twisted.python.failure.Failure錯誤。仔細分析記錄文件scrapy.log,發(fā)現(xiàn)是在下載圖片時變慢的。原因是Scrapy使用了twisted作為異步網絡庫來處理網絡通訊。當下載緩慢時,twisted異步請求發(fā)生錯誤,出現(xiàn)一系列的錯誤回調(errback)或者錯誤回調鏈(errback chain),錯誤會傳遞給下一個errback,errback不返回任何數(shù)據(jù)。而twisted的Deferred對象會使回調函數(shù)把None作為參數(shù)返回,從而導致出錯。
根據(jù)爬取的信息得到表1所示的測試結果表。
根據(jù)表1可得到圖4所示的柱狀圖,在爬取1小時內可以明顯的看出網速一般與網速較好時的差異,網速較好有一定的提升了爬蟲的速度以及下載的數(shù)量。
為了觀察網速對實驗測試產生的影響,下面針對GitHub網站的爬取測試定在早晨6-7點鐘(6MB/S)左右進行測試,得到表2所示的結果。
圖5是根據(jù)表1與表2制成的柱狀圖,可以直觀的看出網速在很好(6MB/S)的情況下,1小時內爬蟲的速度與下載的信息數(shù)據(jù)比網速一般、較好時產生的數(shù)據(jù)多。為保證數(shù)據(jù)的準確性,上述測試前后進行了30余次,取平均值。
綜上,可以得出網速與爬蟲爬取的信息數(shù)量的快慢有關,但是下載的用戶信息數(shù)量與爬取用戶(有重復)的比率是差不多的,從開始的51%左右到1小時內下降至39%下載率。這也跟每個人的關注度有關,若兩人互相關注,重復的抓取下來分析發(fā)現(xiàn)有的已經下載好了,當然這是不可避免的。
4 結語
基于Python的Scrapy框架設計并實現(xiàn)了GitHub爬蟲,從技術上為一些數(shù)據(jù)研究們提供了方便的網絡上數(shù)據(jù)獲取方法。主要特點:
(1)使用方便,只需提供一個用戶的主頁面URL就能利用本文爬蟲抓取GitHub網站中大規(guī)模用戶信息;
(2)支持數(shù)據(jù)庫,所有抓取的信息都保存到MongoDB數(shù)據(jù)庫中,利于統(tǒng)計查詢;
(3)支持大范圍地爬取用戶信息,從一個用戶的URL可得到多個關聯(lián)用戶的URL從而衍生出大量用戶;
(4)圖形界面操縱方便。當所有的數(shù)據(jù)都爬取下來時,可以下載任何用戶的熱門項目。
本GitHub爬蟲在處理重復爬取用戶信息方面,采取了按名字判斷的方法,使重復爬取的次數(shù)得以明顯減少,但是抓取下來的用戶信息也隨之減少了,該問題尚須進一步探索和改進。
(通訊作者:殷旭東)
參考文獻
[1]鄔賀銓.大數(shù)據(jù)時代的機遇與挑戰(zhàn)[J]. 中國經貿,2013(7):32-32.
[2]GitHub中國開發(fā)者年度報告{2014}[EB/OL].[2015-02-03] http://githuber.info/Report.
[3]Manning爬蟲技術淺析[EB/OL].http://drops.wooyun.org/tips/3915.
[4]趙鵬程.分布式書籍網絡爬蟲系統(tǒng)的設計與實現(xiàn)[D].西南交通大學,2014.
[5]趙志.基于NoSQL的BRS系統(tǒng)的設計與實現(xiàn)[D].上海交通大學,2013.
[6]Scrapy研究探索(七)——如何防止被ban之策略大集合[EB/OL].[2014-06-29] http://blog.csdn.net/u012150179/article/details/35774323.
[7]黃聰,李格人,羅楚.大數(shù)據(jù)時代下爬蟲技術的興起[J].計算機光盤軟件與應用,2013(17):79-80.
[8]Twisted 15.4.0 documentation[EB/OL]. http://twistedmatrix.com/documents/current/core/howto/defer.html.
作者簡介
趙本本(1995-),男,常熟理工學院計算機科學與工程學院本科在讀學生。
殷旭東(1970-),男,碩士學位?,F(xiàn)為常熟理工學院計算機科學與工程學院工程師。CCF會員。主要研究方向為移動計算、信息安全。
王偉(1987-),男,碩士學位?,F(xiàn)為蘇州市浪潮電子信息有限公司工程師。主要研究方向為信息安全、大數(shù)據(jù)。
作者單位
1.常熟理工學院計算機科學與工程學院 江蘇省常熟市 215500
2.蘇州市浪潮電子信息有限公司 江蘇省蘇州市 215002