最近在coursera.org(線上學習平臺)上學SNA(Social Network Analysis,社交網路分析)。有興趣的同學可以去看一眼:https://class.coursera.org/sna-002/,課程講的很有意思,等回頭我上完全部課程打算再寫下詳細總結和思考。
為什麼要抓取豆瓣小組資料?
課程要做一個帶程式設計的final project,大概內容就是自己找一個網路資料集,然後按照課程中提供的方法進行分析。其實最難的部分是找資料,兩種方法:自己抓,或者是找現成的。對於後者,國內有個叫資料堂的資料分享網站做的不錯,上面有豆瓣,淘寶,微博等各種資料,不過有些資料需要收費;國外有個叫Konect的網站專注於複雜網路資料。
看了一圈現成的資料都不太滿意,決定自己抓取了。目標鎖定豆瓣小組,打算分析小組之間的互相聯絡。
如何用Scrapy抓取網頁?
還不太瞭解Scrapy的同學直接看這裡http://www.oschina.net/p/scrapy,這邊就不贅述基本功能和安裝方式。
1,先建立一個scrapy專案,專案名稱doubanscrapy startproject douban
1 |
scrapy
startproject douban |
會生成一個專案目錄,內部結構大概如下:
02 |
scrapy.cfg
==> project的配置檔案,一般不用改 |
05 |
items.py
==> 定義抓取的資料結構 |
07 |
settings.py
==》 專案的具體配置,需要更改 |
08 |
spiders/
==》 這個是定義蜘蛛機器人的目錄 |
2, 在item.py中定義要抓取的資料結構:定義了一個DoubanItem,屬性包括name,url, total member number, relative groups, active users。
定義完DoubanItem後,你就可以在實現蜘蛛機器人的程式碼裡返回DoubanItem的例項,Scrapy會自動序列化並匯出到JSON/XML等。
01 |
from scrapy.item import Item,
Field |
03 |
class DoubanItem(Item): |
09 |
RelativeGroups = Field() |
3, 定義一個最簡單的蜘蛛機器人: 抓取豆瓣小組的首頁並儲存在一個檔案裡。我們在spiders目錄下新建一個蜘蛛檔案:BasicGroupSpider.py,程式內容如下:
01 |
from scrapy.spider import BaseSpider |
02 |
from scrapy.item import Item |
03 |
from douban.items import DoubanItem |
05 |
class GroupTestSpider(BaseSpider): |
07 |
allowed_domains = [ "douban.com" ] |
09 |
"http://www.douban.com/group/" , |
12 |
def parse( self ,
response): |
13 |
self .log( "Fetch
douban homepage page: %s" % response.url) |
14 |
open ( "test.data" , "wb" ).write(response.body) |
可以看到:程式擴充套件了BaseSpider類來建立一個自定義的蜘蛛。BaseSpider是Scrapy中自定義的最簡單蜘蛛,它沒有爬行功能,只抓取在start_urls裡面定義的網址,並呼叫parse方法處理每個抓取的response。
然後執行在command line中執行如下命令,將執行上述蜘蛛機器人,並將log寫到test.log中。
1 |
scrapy
crawl Test --logfile= test .log |
4, 接下來要抓取某一個豆瓣小組頁面,例如http://www.douban.com/group/WHV/, 然後解析出小組的名稱,成員總數,以及相關的友情小組和推薦小組的URL——這些資訊將用於構建小組之間的連線。
為此需要引入一個包HTML解析包:
1 |
from scrapy.selector import HtmlXPathSelector |
重新定義 BasicGroupSpider.py如下:
01 |
from scrapy.spider import BaseSpider |
02 |
from scrapy.selector import HtmlXPathSelector |
03 |
from scrapy.item import Item |
04 |
from douban.items import DoubanItem |
07 |
class GroupTestSpider(BaseSpider): |
09 |
allowed_domains = [ "douban.com" ] |
11 |
"http://www.douban.com/group/WHV/" , |
14 |
def __get_id_from_group_url( self ,
url): |
15 |
m = re.search( "^http://www.douban.com/group/([^/]+)/$" ,
url) |
21 |
def parse( self ,
response): |
23 |
self .log( "Fetch
group home page: %s" % response.url) |
25 |
hxs = HtmlXPathSelector(response) |
29 |
item[ 'groupName' ] = hxs.select( '//h1/text()' ).re( "^\s+(.*)\s+$" )[ 0 ] |
32 |
item[ 'groupURL' ] = response.url |
33 |
groupid = self .__get_id_from_group_url(response.url) |
36 |
members_url = "http://www.douban.com/group/%s/members" % groupid |
37 |
members_text = hxs.select( '//a[contains(@href,
"%s")]/text()' % members_url).re( "\((\d+)\)" ) |
38 |
item[ 'totalNumber' ] = members_text[ 0 ] |
41 |
item[ 'RelativeGroups' ] = [] |
42 |
groups = hxs.select( '//div[contains(@class,
"group-list-item")]' ) |
44 |
url = group.select( 'div[contains(@class,
"title")]/a/@href' ).extract()[ 0 ] |
45 |
item[ 'RelativeGroups' ].append(url) |
為了解析抓取到的網頁,parse方法做了較大改動:
- 我們使用了HtmlXPathSelector從response中建立一個dom物件hxs
- 為了得到小組名稱,使用hxs.select('//h1/text()')得到h1標題的內容,然後用re("^\s+(.*)\s+$")過濾到標題的空格
- 為了得到小組的相關小組,使用hxs.select('//div[contains(@class, "group-list-item")]')得到一個小組列表,然後在for迴圈中select小組的URL,並append到item['RelativeGroups']陣列中
執行如下command命令:
1 |
scrapy
crawl Test --logfile= test .log
-o test .json
-t json |
Scrapy會把解析後返回的item序列化為json格式並儲存在test.json檔案中。
到此為止完成了抓取工作的一半——蜘蛛還不能自動爬行來解析網頁,下篇部落格打算講講如何讓蜘蛛在網頁間爬行,以及如何操作cookie等內容。
用Scrapy抓取豆瓣小組資料(二)http://my.oschina.net/chengye/blog/124162