python爬蟲實戰一:分析豆瓣中最新電影的影評

簡介

剛接觸python不久,作一個小項目來練練手。前幾天看了《戰狼2》,發現它在最新上映的電影裏面是排行第一的,以下圖所示。準備把豆瓣上對它的影評(短評)作一個分析。
clipboard.pnghtml

目標總覽

主要作了三件事:python

  • 抓取網頁數據
  • 清理數據
  • 用詞雲進行展現

使用的python版本是3.5.
運行環境:jupyer notebook,如在其餘環境下運行報錯了,請查看評論區的討論,裏面有一些解決辦法。正則表達式

1、抓取網頁數據

第一步要對網頁進行訪問,python中使用的是urllib庫。代碼以下:數組

from urllib import request
resp = 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)能夠查看,以下圖所示:瀏覽器

clipboard.png

第二步,須要對獲得的html代碼進行解析,從裏面提取咱們須要的數據。
在python中使用BeautifulSoup庫進行html代碼的解析。
(注:若是沒有安裝此庫,則使用pip install BeautifulSoup進行安裝便可!)
BeautifulSoup使用的格式以下:app

BeautifulSoup(html,"html.parser")

第一個參數爲須要提取數據的html,第二個參數是指定解析器,而後使用find_all()讀取html標籤中的內容。函數

可是html中有這麼多的標籤,該讀取哪些標籤呢?其實,最簡單的辦法是能夠打開咱們爬取網頁的html代碼,而後查看咱們須要的數據在哪一個html標籤裏面,再進行讀取就能夠了。以下圖所示:字體

clipboard.png

從上圖中能夠看出在div id="nowplaying"標籤開始是咱們想要的數據,裏面有電影的名稱、評分、主演等信息。因此相應的代碼編寫以下:編碼

from bs4 import BeautifulSoup as bs
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_movie_list 是一個列表,能夠用print(nowplaying_movie_list[0])查看裏面的內容,以下圖所示:url

clipboard.png

在上圖中能夠看到data-subject屬性裏面放了電影的id號碼,而在img標籤的alt屬性裏面放了電影的名字,所以咱們就經過這兩個屬性來獲得電影的id和名稱。(注:打開電影短評的網頁時須要用到電影的id,因此須要對它進行解析),編寫代碼以下:

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)

其中列表nowplaying_list中就存放了最新電影的id和名稱,可使用print(nowplaying_list)進行查看,以下圖所示:

clipboard.png

能夠看到和豆瓣網址上面是匹配的。這樣就獲得了最新電影的信息了。接下來就要進行對最新電影短評進行分析了。例如《戰狼2》的短評網址爲:https://movie.douban.com/subject/26363254/comments?start=0&limit=20
其中26363254就是電影的id,start=0表示評論的第0條評論。

接下來接對該網址進行解析了。打開上圖中的短評頁面的html代碼,咱們發現關於評論的數據是在div標籤的comment屬性下面,以下圖所示:

clipboard.png

所以對此標籤進行解析,代碼以下:

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標籤下面存放了網友對電影的評論,以下圖所示:

clipboard.png

所以對comment_div_lits 代碼中的html代碼繼續進行解析,代碼以下:

eachCommentList = []; 
for item in comment_div_lits: 
        if item.find_all('p')[0].string is not None:     
            eachCommentList.append(item.find_all('p')[0].string)

使用print(eachCommentList)查看eachCommentList列表中的內容,能夠看到裏面存裏咱們想要的影評。以下圖所示:

clipboard.png

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

2、數據清洗

爲了方便進行數據進行清洗,咱們將列表中的數據放在一個字符串數組中,代碼以下:

comments = ''
for k in range(len(eachCommentList)):
    comments = comments + (str(eachCommentList[k])).strip()

使用print(comments)進行查看,以下圖所示:

clipboard.png

能夠看到全部的評論已經變成一個字符串了,可是咱們發現評論中還有很多的標點符號等。這些符號對咱們進行詞頻統計時根本沒有用,所以要將它們清除。所用的方法是正則表達式。python中正則表達式是經過re模塊來實現的。代碼以下:

import re

pattern = re.compile(r'[\u4e00-\u9fa5]+')
filterdata = re.findall(pattern, comments)
cleaned_comments = ''.join(filterdata)

繼續使用print(cleaned_comments)語句進行查看,以下圖所示:

clipboard.png
咱們能夠看到此時評論數據中已經沒有那些標點符號了,數據變得「乾淨」了不少。

所以要進行詞頻統計,因此先要進行中文分詞操做。在這裏我使用的是結巴分詞。若是沒有安裝結巴分詞,能夠在控制檯使用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()語句來查看結果,以下圖所示,停用詞已經被除去了。

clipboard.png

接下來就要進行詞頻統計了,代碼以下:

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()進行查看,結果以下:

clipboard.png

因爲咱們前面只是爬取了第一頁的評論,因此數據有點少,在最後給出的完整代碼中,我爬取了10頁的評論,因此數據仍是有必定參考價值的。

3、用詞雲進行顯示

代碼以下:

import matplotlib.pyplot as plt
%matplotlib inline
import matplotlib
matplotlib.rcParams['figure.figsize'] = (10.0, 5.0)
from wordcloud import WordCloud#詞雲包

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)

其中simhei.ttf使用來指定字體的,能夠在百度上輸入simhei.ttf進行下載後,放入程序的根目錄便可。顯示的圖像以下:

clipboard.png

到此爲止,整個項目的介紹就結束了。因爲本身也仍是個初學者,接觸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()

結果顯示以下:

clipboard.png

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

相關文章
相關標籤/搜索