python爬蟲實戰一:分析豆瓣中最新電影的影評
簡介
剛接觸python不久,做一個小專案來練練手。前幾天看了《戰狼2》,發現它在最新上映的電影裡面是排行第一的,如下圖所示。準備把豆瓣上對它的影評(短評)做一個分析。

目標總覽
主要做了三件事:
抓取網頁資料
清理資料
用詞雲進行展示
使用的python版本是3.5.
執行環境:jupyer notebook, 如在其他環境下執行報錯了,請檢視評論區的討論,裡面有一些解決辦法。
一、抓取網頁資料
第一步要對網頁進行訪問,python中使用的是urllib庫。程式碼如下:
from urllibimportrequestresp = request.urlopen('https://movie.douban.com/nowplaying/hangzhou/')html_data = resp.read().decode('utf-8')
其中 https://movie.douban.com/nowp... ,可以在瀏覽器中輸入該網址進行檢視。
html_data是字串型別的變數,裡面存放了網頁的html程式碼。
輸入print(html_data)可以檢視,如下圖所示:

第二步,需要對得到的html程式碼進行解析,從裡面提取我們需要的資料。
在python中使用BeautifulSoup庫進行html程式碼的解析。
(注:如果沒有安裝此庫,則使用pip install BeautifulSoup進行安裝即可!)
BeautifulSoup使用的格式如下:
BeautifulSoup(html,"html.parser")
第一個引數為需要提取資料的html,第二個引數是指定解析器,然後使用find_all()讀取html標籤中的內容。
但是html中有這麼多的標籤,該讀取哪些標籤呢?其實,最簡單的辦法是可以開啟我們爬取網頁的html程式碼,然後檢視我們需要的資料在哪個html標籤裡面,再進行讀取就可以了。如下圖所示:

從上圖中可以看出在div id="nowplaying"標籤開始是我們想要的資料,裡面有電影的名稱、評分、主演等資訊。所以相應的程式碼編寫如下:
frombs4importBeautifulSoupasbssoup = bs(html_data,'html.parser') nowplaying_movie = soup.find_all('div', id='nowplaying')nowplaying_movie_list = nowplaying_movie[0].find_all('li', class_='list-item')
其中nowplaying_movie_list 是一個列表,可以用print(nowplaying_movie_list[0])檢視裡面的內容,如下圖所示:

python學習交流群:923414804,群內每天分享乾貨,包括最新的企業級案例學習資料和零基礎入門教程,歡迎小夥伴入群學習。
在上圖中可以看到data-subject屬性裡面放了電影的id號碼,而在img標籤的alt屬性裡面放了電影的名字,因此我們就通過這兩個屬性來得到電影的id和名稱。(注:開啟電影短評的網頁時需要用到電影的id,所以需要對它進行解析),編寫程式碼如下:
nowplaying_list = []foriteminnowplaying_movie_list:nowplaying_dict = {} nowplaying_dict['id'] = item['data-subject']fortag_img_iteminitem.find_all('img'): nowplaying_dict['name'] = tag_img_item['alt'] nowplaying_list.append(nowplaying_dict)
其中列表nowplaying_list中就存放了最新電影的id和名稱,可以使用print(nowplaying_list)進行檢視,如下圖所示:

可以看到和豆瓣網址上面是匹配的。這樣就得到了最新電影的資訊了。接下來就要進行對最新電影短評進行分析了。例如《戰狼2》的短評網址為:https://movie.douban.com/subject/26363254/comments?start=0&limit=20
其中26363254就是電影的id,start=0表示評論的第0條評論。
接下來接對該網址進行解析了。開啟上圖中的短評頁面的html程式碼,我們發現關於評論的資料是在div標籤的comment屬性下面,如下圖所示:

因此對此標籤進行解析,程式碼如下:
requrl='https://movie.douban.com/subject/'+ nowplaying_list[0]['id'] +'/comments'+'?'+'start=0'+'&limit=20'resp= request.urlopen(requrl)html_data= resp.read().decode('utf-8')soup= bs(html_data,'html.parser')comment_div_lits= soup.find_all('div', class_='comment')
此時在comment_div_lits 列表中存放的就是div標籤和comment屬性下面的html程式碼了。在上圖中還可以發現在p標籤下面存放了網友對電影的評論,如下圖所示:

因此對comment_div_lits 程式碼中的html程式碼繼續進行解析,程式碼如下:
eachCommentList = [];foritemincomment_div_lits:ifitem.find_all('p')[0].stringisnotNone: eachCommentList.append(item.find_all('p')[0].string)
使用print(eachCommentList)檢視eachCommentList列表中的內容,可以看到裡面存裡我們想要的影評。如下圖所示:

好的,至此我們已經爬取了豆瓣最近播放電影的評論資料,接下來就要對資料進行清洗和詞雲顯示了。
二、資料清洗
為了方便進行資料進行清洗,我們將列表中的資料放在一個字串陣列中,程式碼如下:
comments =''forkinrange(len(eachCommentList)): comments = comments + (str(eachCommentList[k])).strip()
使用print(comments)進行檢視,如下圖所示:

可以看到所有的評論已經變成一個字串了,但是我們發現評論中還有不少的標點符號等。這些符號對我們進行詞頻統計時根本沒有用,因此要將它們清除。所用的方法是正則表示式。python中正則表示式是通過re模組來實現的。程式碼如下:
importrepattern = re.compile(r'[\u4e00-\u9fa5]+')filterdata = re.findall(pattern, comments)cleaned_comments =''.join(filterdata)
繼續使用print(cleaned_comments)語句進行檢視,如下圖所示:

我們可以看到此時評論資料中已經沒有那些標點符號了,資料變得“乾淨”了很多。
因此要進行詞頻統計,所以先要進行中文分詞操作。在這裡我使用的是結巴分詞。如果沒有安裝結巴分詞,可以在控制檯使用pip install jieba進行安裝。(注:可以使用pip list檢視是否安裝了這些庫)。程式碼如下所示:
import jieba#分詞包import pandas as pd segment = jieba.lcut(cleaned_comments)words_df=pd.DataFrame({'segment':segment})
因為結巴分詞要用到pandas,所以我們這裡載入了pandas包。可以使用words_df.head()檢視分詞之後的結果,如下圖所示:

從上圖可以看到我們的資料中有“看”、“太”、“的”等虛詞(停用詞),而這些詞在任何場景中都是高頻詞,並且沒有實際的含義,所以我們要將他們清除。
我把停用詞放在一個stopwords.txt檔案中,將我們的資料與停用詞進行比對即可(注:只要在百度中輸入stopwords.txt,就可以下載到該檔案)。去停用詞程式碼如下:
stopwords=pd.read_csv("stopwords.txt",index_col=False,quoting=3,sep="\t",names=['stopword'], encoding='utf-8')#quoting=3全不引用words_df=words_df[~words_df.segment.isin(stopwords.stopword)]
繼續使用words_df.head()語句來檢視結果,如下圖所示,停用詞已經被除去了。

接下來就要進行詞頻統計了,程式碼如下:
import numpy#numpy計算包words_stat=words_df.groupby(by=['segment'])['segment'].agg({"計數":numpy.size})words_stat=words_stat.reset_index().sort_values(by=["計數"],ascending=False)
用words_stat.head()進行檢視,結果如下:

由於我們前面只是爬取了第一頁的評論,所以資料有點少,在最後給出的完整程式碼中,我爬取了10頁的評論,所以資料還是有一定參考價值的。
三、用詞雲進行顯示
程式碼如下:
importmatplotlib.pyplotasplt%matplotlib inlineimportmatplotlibmatplotlib.rcParams['figure.figsize'] = (10.0,5.0)fromwordcloudimportWordCloud#詞雲包wordcloud=WordCloud(font_path="simhei.ttf",background_color="white",max_font_size=80)#指定字型型別、字型大小和字型顏色word_frequence = {x[0]:x[1]forxinwords_stat.head(1000).values}word_frequence_list = []forkeyinword_frequence: temp = (key,word_frequence[key]) word_frequence_list.append(temp)wordcloud=wordcloud.fit_words(word_frequence_list)plt.imshow(wordcloud)
其中simhei.ttf使用來指定字型的,可以在百度上輸入simhei.ttf進行下載後,放入程式的根目錄即可。顯示的影象如下:

到此為止,整個專案的介紹就結束了。由於自己也還是個初學者,接觸python不久,程式碼寫的並不好。而且第一次寫技術部落格,表達的有些冗餘,請大家多多包涵,有不對的地方,請大家批評指正。以後我也會將自己做的小專案以這種形式寫在部落格上和大家一起交流!最後貼上完整的程式碼。
完整程式碼
#coding:utf-8
__author__ = 'hang'
import warnings
warnings.filterwarnings("ignore")
import jieba #分詞包
import numpy #numpy計算包
import codecs #codecs提供的open方法來指定開啟的檔案的語言編碼,它會在讀取的時候自動轉換為內部unicode
import re
import pandas as pd
import matplotlib.pyplot as plt
from urllib import request
from bs4 import BeautifulSoup as bs
%matplotlib inline
import matplotlib
matplotlib.rcParams['figure.figsize'] = (10.0, 5.0)
from wordcloud import WordCloud#詞雲包
#分析網頁函式
def getNowPlayingMovie_list():
resp = request.urlopen('https://movie.douban.com/nowplaying/hangzhou/')
html_data = resp.read().decode('utf-8')
soup = bs(html_data, 'html.parser')
nowplaying_movie = soup.find_all('div', id='nowplaying')
nowplaying_movie_list = nowplaying_movie[0].find_all('li', class_='list-item')
nowplaying_list = []
for item in nowplaying_movie_list:
nowplaying_dict = {}
nowplaying_dict['id'] = item['data-subject']
for tag_img_item in item.find_all('img'):
nowplaying_dict['name'] = tag_img_item['alt']
nowplaying_list.append(nowplaying_dict)
return nowplaying_list
#爬取評論函式
def getCommentsById(movieId, pageNum):
eachCommentList = [];
if pageNum>0:
start = (pageNum-1) * 20
else:
return False
requrl = 'https://movie.douban.com/subject/' + movieId + '/comments' +'?' +'start=' + str(start) + '&limit=20'
print(requrl)
resp = request.urlopen(requrl)
html_data = resp.read().decode('utf-8')
soup = bs(html_data, 'html.parser')
comment_div_lits = soup.find_all('div', class_='comment')
for item in comment_div_lits:
if item.find_all('p')[0].string is not None:
eachCommentList.append(item.find_all('p')[0].string)
return eachCommentList
def main():
#迴圈獲取第一個電影的前10頁評論
commentList = []
NowPlayingMovie_list = getNowPlayingMovie_list()
for i in range(10):
num = i + 1
commentList_temp = getCommentsById(NowPlayingMovie_list[0]['id'], num)
commentList.append(commentList_temp)
#將列表中的資料轉換為字串
comments = ''
for k in range(len(commentList)):
comments = comments + (str(commentList[k])).strip()
#使用正則表示式去除標點符號
pattern = re.compile(r'[\u4e00-\u9fa5]+')
filterdata = re.findall(pattern, comments)
cleaned_comments = ''.join(filterdata)
#使用結巴分詞進行中文分詞
segment = jieba.lcut(cleaned_comments)
words_df=pd.DataFrame({'segment':segment})
#去掉停用詞
stopwords=pd.read_csv("stopwords.txt",index_col=False,quoting=3,sep="\t",names=['stopword'], encoding='utf-8')#quoting=3全不引用
words_df=words_df[~words_df.segment.isin(stopwords.stopword)]
#統計詞頻
words_stat=words_df.groupby(by=['segment'])['segment'].agg({"計數":numpy.size})
words_stat=words_stat.reset_index().sort_values(by=["計數"],ascending=False)
#用詞雲進行顯示
wordcloud=WordCloud(font_path="simhei.ttf",background_color="white",max_font_size=80)
word_frequence = {x[0]:x[1] for x in words_stat.head(1000).values}
word_frequence_list = []
for key in word_frequence:
temp = (key,word_frequence[key])
word_frequence_list.append(temp)
wordcloud=wordcloud.fit_words(word_frequence_list)
plt.imshow(wordcloud)
#主函式
main()
結果顯示如下:

上圖基本反映了《戰狼2》這部電影的情況。PS:我本人並不喜歡這部電影,內容太空洞、太假,為了愛國而愛國,沒意思。哎,這兩年真是國產電影的低谷啊,沒有一部拿得出手的國產電影,看看人家印度拍的《摔跤吧,爸爸》那才是拍的有深度,同樣是表現愛國,國產電影還是需要向別的國家好好學學。