歡迎光臨
每天分享高質量文章

Python爬蟲實戰:《戰狼2》豆瓣影評分析

作者:hang

來自:https://segmentfault.com/a/1190000010473819

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

標的總覽

主要做了三件事:

  • 抓取網頁資料

  • 清理資料

  • 用詞雲進行展示 
    使用的python版本是3.5.

一、抓取網頁資料

第一步要對網頁進行訪問,python中使用的是urllib庫。程式碼如下:

  1. from urllib import request

  2. resp = request.urlopen('https://movie.douban.com/nowplaying/hangzhou/')

  3. 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使用的格式如下:

  1. BeautifulSoup(html,"html.parser")

第一個引數為需要提取資料的html,第二個引數是指定解析器,然後使用 find_all()讀取html標簽中的內容。

但是html中有這麼多的標簽,該讀取哪些標簽呢?其實,最簡單的辦法是我們可以開啟我們爬取網頁的html程式碼,然後檢視我們需要的資料在哪個html標簽裡面,再進行讀取就可以了。如下圖所示:

從上圖中可以看出在 div id="nowplaying"標簽開始是我們想要的資料,裡面有電影的名稱、評分、主演等資訊。所以相應的程式碼編寫如下:

  1. from bs4 import BeautifulSoup as bs

  2. soup = bs(html_data, 'html.parser')    

  3. nowplaying_movie = soup.find_all('div', id='nowplaying')

  4. nowplaying_movie_list = nowplaying_movie[0].find_all('li', class_='list-item')

其中 nowplaying_movie_list是一個串列,可以用 print(nowplaying_movie_list[0])檢視裡面的內容,如下圖所示:

在上圖中可以看到data-subject屬性裡面放了電影的id號碼,而在img標簽的alt屬性裡面放了電影的名字,因此我們就透過這兩個屬性來得到電影的id和名稱。(註:開啟電影短評的網頁時需要用到電影的id,所以需要對它進行解析),編寫程式碼如下:

  1. nowplaying_list = []

  2. for item in nowplaying_movie_list:        

  3.        nowplaying_dict = {}        

  4.        nowplaying_dict['id'] = item['data-subject']      

  5.        for tag_img_item in item.find_all('img'):            

  6.            nowplaying_dict['name'] = tag_img_item['alt']            

  7.            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屬性下麵,如下圖所示:

因此對此標簽進行解析,程式碼如下:

  1. requrl = 'https://movie.douban.com/subject/' + nowplaying_list[0]['id'] + '/comments' +'?' +'start=0' + '&limit;=20'

  2. resp = request.urlopen(requrl)

  3. html_data = resp.read().decode('utf-8')

  4. soup = bs(html_data, 'html.parser')

  5. comment_div_lits = soup.find_all('div', class_='comment')

此時在 comment_div_lits串列中存放的就是div標簽和comment屬性下麵的html程式碼了。在上圖中還可以發現在p標簽下麵存放了網友對電影的評論,如下圖所示:

因此對 comment_div_lits程式碼中的html程式碼繼續進行解析,程式碼如下:

  1. eachCommentList = [];

  2. for item in comment_div_lits:

  3.        if item.find_all('p')[0].string is not None:    

  4.            eachCommentList.append(item.find_all('p')[0].string)

使用 print(eachCommentList)檢視eachCommentList串列中的內容,可以看到裡面存裡我們想要的影評。如下圖所示:

好的,至此我們已經爬取了豆瓣最近播放電影的評論資料,接下來就要對資料進行清洗和詞雲顯示了。

二、資料清洗

為了方便進行資料進行清洗,我們將串列中的資料放在一個字串陣列中,程式碼如下:

  1. comments = ''

  2. for k in range(len(eachCommentList)):

  3.    comments = comments + (str(eachCommentList[k])).strip()

使用 print(comments)進行檢視,如下圖所示:

可以看到所有的評論已經變成一個字串了,但是我們發現評論中還有不少的標點符號等。這些符號對我們進行詞頻統計時根本沒有用,因此要將它們清除。所用的方法是正則運算式。python中正則運算式是透過re模組來實現的。程式碼如下:

  1. import re

  2. pattern = re.compile(r'[u4e00-u9fa5]+')

  3. filterdata = re.findall(pattern, comments)

  4. cleaned_comments = ''.join(filterdata)

繼續使用 print(cleaned_comments)陳述句進行檢視,如下圖所示:

我們可以看到此時評論資料中已經沒有那些標點符號了,資料變得"乾凈"了很多。

因此要進行詞頻統計,所以先要進行中文分詞操作。在這裡我使用的是結巴分詞。如果沒有安裝結巴分詞,可以在控制檯使用 pip install jieba進行安裝。(註:可以使用 pip list檢視是否安裝了這些庫)。程式碼如下所示:

  1. import jieba    #分詞包

  2. import pandas as pd  

  3. segment = jieba.lcut(cleaned_comments)

  4. words_df=pd.DataFrame({'segment':segment})

因為結巴分詞要用到pandas,所以我們這裡載入了pandas包。可以使用 words_df.head()檢視分詞之後的結果,如下圖所示:

從上圖可以看到我們的資料中有"看"、"太"、"的"等虛詞(停用詞),而這些詞在任何場景中都是高頻時,並且沒有實際的含義,所以我們要他們進行清除。

我把停用詞放在一個 stopwords.txt檔案中,將我們的資料與停用詞進行比對即可(註:只要在百度中輸入 stopwords.txt,就可以下載到該檔案)。去停用詞程式碼如下程式碼如下:

  1. stopwords=pd.read_csv("stopwords.txt",index_col=False,quoting=3,sep="t",names=['stopword'], encoding='utf-8')#quoting=3全不取用

  2. words_df=words_df[~words_df.segment.isin(stopwords.stopword)]

繼續使用 words_df.head()陳述句來檢視結果,如下圖所示,停用詞已經被出去了。

接下來就要進行詞頻統計了,程式碼如下:

  1. import numpy    #numpy計算包

  2. words_stat=words_df.groupby(by=['segment'])['segment'].agg({"計數":numpy.size})

  3. words_stat=words_stat.reset_index().sort_values(by=["計數"],ascending=False)

用 words_stat.head()進行檢視,結果如下:

由於我們前面只是爬取了第一頁的評論,所以資料有點少,在最後給出的完整程式碼中,我爬取了10頁的評論,所資料還是有參考價值。

三、用詞雲進行顯示

程式碼如下:

  1. import matplotlib.pyplot as plt

  2. %matplotlib inline

  3. import matplotlib

  4. matplotlib.rcParams['figure.figsize'] = (10.0, 5.0)

  5. from wordcloud import WordCloud#詞雲包

  6. wordcloud=WordCloud(font_path="simhei.ttf",background_color="white",max_font_size=80) #指定字型型別、字型大小和字型顏色

  7. word_frequence = {x[0]:x[1] for x in words_stat.head(1000).values}

  8. word_frequence_list = []

  9. for key in word_frequence:

  10.    temp = (key,word_frequence[key])

  11.    word_frequence_list.append(temp)

  12. wordcloud=wordcloud.fit_words(word_frequence_list)

  13. plt.imshow(wordcloud)

其中 simhei.ttf使用來指定字型的,可以在百度上輸入 simhei.ttf進行下載後,放入程式的根目錄即可。顯示的影象如下:

到此為止,整個專案的介紹就結束了。由於自己也還是個初學者,接觸python不久,程式碼寫的並不好。而且第一次寫技術部落格,表達的有些冗餘,請大家多多包涵,有不對的地方,請大家批評指正。以後我也會將自己做的小專案以這種形式寫在部落格上和大家一起交流!最後貼上完整的程式碼。

完整程式碼

  1. #coding:utf-8

  2. __author__ = 'hang'

  3. import warnings

  4. warnings.filterwarnings("ignore")

  5. import jieba    #分詞包

  6. import numpy    #numpy計算包

  7. import codecs   #codecs提供的open方法來指定開啟的檔案的語言編碼,它會在讀取的時候自動轉換為內部unicode

  8. import re

  9. import pandas as pd  

  10. import matplotlib.pyplot as plt

  11. from urllib import request

  12. from bs4 import BeautifulSoup as bs

  13. %matplotlib inline

  14. import matplotlib

  15. matplotlib.rcParams['figure.figsize'] = (10.0, 5.0)

  16. from wordcloud import WordCloud#詞雲包

  17. #分析網頁函式

  18. def getNowPlayingMovie_list():  

  19.    resp = request.urlopen('https://movie.douban.com/nowplaying/hangzhou/')        

  20.    html_data = resp.read().decode('utf-8')    

  21.    soup = bs(html_data, 'html.parser')    

  22.    nowplaying_movie = soup.find_all('div', id='nowplaying')        

  23.    nowplaying_movie_list = nowplaying_movie[0].find_all('li', class_='list-item')    

  24.    nowplaying_list = []    

  25.    for item in nowplaying_movie_list:        

  26.        nowplaying_dict = {}        

  27.        nowplaying_dict['id'] = item['data-subject']      

  28.        for tag_img_item in item.find_all('img'):            

  29.            nowplaying_dict['name'] = tag_img_item['alt']            

  30.            nowplaying_list.append(nowplaying_dict)    

  31.    return nowplaying_list

  32. #爬取評論函式

  33. def getCommentsById(movieId, pageNum):

  34.    eachCommentList = [];

  35.    if pageNum>0:

  36.         start = (pageNum-1) * 20

  37.    else:

  38.        return False

  39.    requrl = 'https://movie.douban.com/subject/' + movieId + '/comments' +'?' +'start=' + str(start) + '&limit;=20'

  40.    print(requrl)

  41.    resp = request.urlopen(requrl)

  42.    html_data = resp.read().decode('utf-8')

  43.    soup = bs(html_data, 'html.parser')

  44.    comment_div_lits = soup.find_all('div', class_='comment')

  45.    for item in comment_div_lits:

  46.        if item.find_all('p')[0].string is not None:    

  47.            eachCommentList.append(item.find_all('p')[0].string)

  48.    return eachCommentList

  49. def main():

  50.    #迴圈獲取第一個電影的前10頁評論

  51.    commentList = []

  52.    NowPlayingMovie_list = getNowPlayingMovie_list()

  53.    for i in range(10):    

  54.        num = i + 1

  55.        commentList_temp = getCommentsById(NowPlayingMovie_list[0]['id'], num)

  56.        commentList.append(commentList_temp)

  57.    #將串列中的資料轉換為字串

  58.    comments = ''

  59.    for k in range(len(commentList)):

  60.        comments = comments + (str(commentList[k])).strip()

  61.    #使用正則運算式去除標點符號

  62.    pattern = re.compile(r'[u4e00-u9fa5]+')

  63.    filterdata = re.findall(pattern, comments)

  64.    cleaned_comments = ''.join(filterdata)

  65.    #使用結巴分詞進行中文分詞

  66.    segment = jieba.lcut(cleaned_comments)

  67.    words_df=pd.DataFrame({'segment':segment})

  68.    #去掉停用詞

  69.    stopwords=pd.read_csv("stopwords.txt",index_col=False,quoting=3,sep="t",names=['stopword'], encoding='utf-8')#quoting=3全不取用

  70.    words_df=words_df[~words_df.segment.isin(stopwords.stopword)]

  71.    #統計詞頻

  72.    words_stat=words_df.groupby(by=['segment'])['segment'].agg({"計數":numpy.size})

  73.    words_stat=words_stat.reset_index().sort_values(by=["計數"],ascending=False)

  74.    #用詞雲進行顯示

  75.    wordcloud=WordCloud(font_path="simhei.ttf",background_color="white",max_font_size=80)

  76.    word_frequence = {x[0]:x[1] for x in words_stat.head(1000).values}

  77.    word_frequence_list = []

  78.    for key in word_frequence:

  79.        temp = (key,word_frequence[key])

  80.        word_frequence_list.append(temp)

  81.    wordcloud=wordcloud.fit_words(word_frequence_list)

  82.    plt.imshow(wordcloud)

  83. #主函式

  84. main()

結果顯示如下:

上圖基本反映了《戰狼2》這部電影的情況。


●編號374,輸入編號直達本文

●輸入m獲取文章目錄

推薦↓↓↓

 

演演算法與資料結構

更多推薦:18個技術類微信公眾號

涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。

贊(0)

分享創造快樂

© 2024 知識星球   網站地圖