數據格式:
cmt_id: 影評ID編號, 主鍵
cmt_cont: 未切割影評數據(原始影評數據)
cmt_star: 評分(星數)
cmt_time: 發布時間
cmt_user: 發布者url
cmt_thumbs: 評論點贊數
評論星數
評論星數在html網頁dom結構中對應的標簽:<span class="allstar20 rating" title="較差"></span>
星數的映射關系為:
1顆星:很差
2顆星:較差
3顆星:還行
4顆星:推薦
5顆星:力薦
抽取過程中,將以數字代表星數,不記錄文字表述
項目構建步驟
一、 利用virtualenv創建虛擬沙盒
mkdir DouBanMovieProVenv
virtualenv —distribute DouBanMovieProVenv/
cd DouBanMovieProVenv/
# 啟動虛擬環境
source bin/activate
二、安裝依賴包
pip install scrapy
pip install pymongo
pip install beautifulsoup4
三、創建scrapy項目
創建scrapy項目, 用來實現影評數據的抓取
scrapy start project JediEscapePro
四 、擼代碼啦
scrapy爬蟲構建過程:
scrapy項目過程分為四個模塊, 即分別定義item, spider, pipeline, settings
1、定義item
item項對應影評數據結構,基本就是你要從抓取的網頁中提取的元數據, 實際上就是一個comment對象
item :
--- cmt_id
--- cmt_cont
--- cmt_star
--- cmt_time
--- cmt_user
--- cmt_thumbs
2、抓取網頁,提取item元數據
通過對影評html網頁的分析,發現每條影評對應一個div[@class="comment-item"]標簽,該標簽中包含了我們需要提取的各個item項,對應關系如下:
--- cmt_id: 對應div標簽的data-cid屬性值
--- cmt_cont:div標簽的子標簽p的text值
--- cmt_star:span[@class='comment-info']的子標簽span的title屬性值
--- cmt_time:span[@class='comment-info']的子標簽span的text值,直接用正則匹配re("\d{4}-\d{2}-\d{2}")[0]
--- cmt_user:span[@class='comment-info']的子標簽a的href屬性值
--- cmt_thumbs:span[@class='comment-vote']的子標簽span的文本值
得出各個item項對應的標簽元素,利用xpath進行索引,獲取元素信息。xpath的內容請參考:http://www.w3school.com.cn/xpath/
3、定義pipeline
本項目使用面向文檔的mongoDB數據庫,方便以后影評數據字段的動態擴充。此處主要定義一些基本的增刪改查操作,需要注意的是:
在抓取過程中,將通過已有記錄實現重復記錄的過濾,避免重復抓取。為了應對反爬蟲,將對抓取頻率進行限制,並可能多次抓取,在此過程中評論的點贊數
是可能更新的,因此將對cmt_thumbs實現實時更新。
4、settings設置
// 設置5秒內的隨機延遲
DOWNLOAD_DELAY = 5
RANDOMIZE_DOWNLOAD_DELAY = True
// 多個用戶代理,隨機切換
USER_AGENT_LIST =[...]
// 多個cookie,隨機切換
COOKIES = [...]
5、反反爬蟲策略
豆瓣影評數據未登陸狀態下,只能抓取200條左右,因此探索過程中,采取了模擬表單登陸
1)表單提交登陸
form_data = {
'source': 'movie',
'redir': "https://movie.douban.com/subject/24529353/comments?start=20",
'form_email': 'your email',
'form_password': 'your password',
'remember': "on",
'login': "登錄".decode("utf-8")
}
return [FormRequest.from_response(response,
meta={'cookiejar': response.meta['cookiejar']},
headers=self.headers,
formdata=form_data,
callback=self.after_login,
dont_filter=True)]
表單登陸能夠成功,僅限於未出現驗證碼的情況,有驗證碼后,嘗試過假如驗證碼信息,但未成功,也嘗試過識別驗證碼,效果不佳。
2) 帶cookie請求,模擬登陸
因此,選擇了帶cookie請求的方式:首先,利用firefox從瀏覽器端正常登陸豆瓣,登陸成功后獲取到當前cookie信息,拷貝到settings中的COOKIES。
在請求網頁時,采用如下方式,帶上cookie信息,就可以正常請求了:
for url in response.xpath("//a[@class='next']/@href").extract():
yield Request('https://movie.douban.com/subject/24529353/comments'+url,
callback=self.parse, cookies=random.choice(COOKIES))
response.xpath(...)提取的下一頁的鏈接。
6、評論者信息抓取
對於評論者信息的抓取,簡單采用urlli2模塊即可,url來源於cmt_user。抓取過程中,同樣帶上cookie信息。抓取的數據項包括:
url: 用戶主頁鏈接(已有)
area: 用戶所屬地區,如“江蘇南京”
join_time: 用戶注冊時間
nick_name: 用戶昵稱
7、數據簡單分析
對所獲取的影評數據從評星數,相關星級點贊數兩個方面進行統計分析,如下:
可以看出,該片整體市場反應一般,評分不高
對抓取得到的一萬多個用戶數據進行分析,得出這些用戶共來自於國內外的520的區域,占有率較高的前15個區域人數和占比如下:
用戶相關:
total area is: 520
area -> counts: None, 2111 // 用戶注冊未登錄區域信息可能
area -> counts: 北京, 1323
area -> counts: 上海, 878
area -> counts: 四川成都, 490
area -> counts: 廣東廣州, 483
area -> counts: 浙江杭州, 409
area -> counts: 湖北武漢, 347
area -> counts: 廣東深圳, 345
area -> counts: 江蘇南京, 289
area -> counts: 重慶, 283
area -> counts: 陝西西安, 262
area -> counts: 湖南長沙, 241
area -> counts: 天津, 184
area -> counts: 江蘇蘇州, 155
area -> counts: 河南鄭州, 135
8、詞雲展現
對所有影評數據做分詞、去停用詞處理,去掉詞長為1的詞,獲取詞頻統計信息后,得出的詞雲如下:
五、解決的問題
1、 403錯誤
定義UserAgent, request帶cookie
cookie的獲取:
首先,用自己的賬號登陸,利用google chrome 或者 firefox 得到cookie信息, 將 cookie拷貝到本地,防置在request中, 如下:
for url in response.xpath("//a[@class='next']/@href").extract():
yield Request('https://movie.douban.com/subject/24529353/comments'+url, callback=self.parse, cookies=cookie)
2、 未登錄抓取有限
模擬cookie登錄
3、 模擬表單提交登錄
表單提交登陸,在有驗證碼時登陸未成功,不知道什么問題
form_data = {
'source': 'movie',
'redir': "https://movie.douban.com/subject/24529353/comments?start=20",
'form_email': 'your email',
'form_password': 'your password',
'remember': "on",
'login': "登錄".decode("utf-8")
}
return [FormRequest.from_response(response,
meta={'cookiejar': response.meta['cookiejar']},
headers=self.headers,
formdata=form_data,
callback=self.after_login,
dont_filter=True)]
4、解決驗證碼問題
ocr驗證碼識別,但未成功
5、wordcloud詞雲顯示中文亂碼
wc = WordCloud(background_color="white", max_words=2000, mask=alice_coloring, max_font_size=40,
random_state=42, font_path="/Library/Fonts/Kaiti.ttc")
加入font_path,指向本地系統的楷體字體路徑(mac os)