用Scrapy抓取豆瓣小組資料(一)

鴨脖發表於2014-03-19

最近在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

會生成一個專案目錄,內部結構大概如下:

01 douban/
02     scrapy.cfg  ==> project的配置檔案,一般不用改
03     douban/
04         __init__.py
05         items.py  ==> 定義抓取的資料結構
06         pipelines.py
07         settings.py ==》 專案的具體配置,需要更改
08         spiders/    ==》 這個是定義蜘蛛機器人的目錄
09             __init__.py
10             ...
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
02  
03 class DoubanItem(Item):
04     # define the fields for your item here like:
05     # name = Field()
06     groupName = Field()
07     groupURL = Field()
08     totalNumber = Field()
09     RelativeGroups = Field()
10     ActiveUesrs = Field()

3, 定義一個最簡單的蜘蛛機器人: 抓取豆瓣小組的首頁並儲存在一個檔案裡。我們在spiders目錄下新建一個蜘蛛檔案:BasicGroupSpider.py,程式內容如下:

01 from scrapy.spider import BaseSpider
02 from scrapy.item import Item
03 from douban.items import DoubanItem
04  
05 class GroupTestSpider(BaseSpider):
06     name = "Test"
07     allowed_domains = ["douban.com"]
08     start_urls = [
09         "http://www.douban.com/group/",
10     ]
11  
12     def parse(self, response):
13         self.log("Fetch douban homepage page: %s" % response.url)
14         open("test.data""wb").write(response.body)
15         

可以看到:程式擴充套件了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
05 import re
06  
07 class GroupTestSpider(BaseSpider):
08     name = "Test"
09     allowed_domains = ["douban.com"]
10     start_urls = [
11         "http://www.douban.com/group/WHV/",
12     ]
13  
14     def __get_id_from_group_url(self, url):
15         =  re.search("^http://www.douban.com/group/([^/]+)/$", url)
16         if(m):
17             return m.group(1)
18         else:
19             return 0
20  
21     def parse(self, response):
22          
23         self.log("Fetch group home page: %s" % response.url)
24  
25         hxs = HtmlXPathSelector(response)
26         item = DoubanItem()
27  
28         #get group name
29         item['groupName'= hxs.select('//h1/text()').re("^\s+(.*)\s+$")[0]
30  
31         #get group id
32         item['groupURL'= response.url
33         groupid = self.__get_id_from_group_url(response.url)
34  
35         #get group members number
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]
39  
40         #get relative groups
41         item['RelativeGroups'= []
42         groups = hxs.select('//div[contains(@class, "group-list-item")]')
43         for group in groups:
44             url = group.select('div[contains(@class, "title")]/a/@href').extract()[0]
45             item['RelativeGroups'].append(url)
46         #item['RelativeGroups'] = ','.join(relative_groups)
47         return item
為了解析抓取到的網頁,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

相關文章