《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

黃渤首次導演的電影《一出好戲》自8月10日在全國上映,至今已有10天,其主演陣容強大,相信許多觀衆也都是衝着明星們去的。
目前《一出好戲》在貓眼上已經得到近60萬個評價,評分爲8.2分,票房已破10億。html

《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

做者本人(湯小洋 )今天也走進了電影院,對這部電影作了親身的觀看,看完後的感受是有些許失落的,本覺得是喜劇片,結果發現笑點通常,從搞笑的角度來看,不如《西虹市首富》,影片更多的是反映人類本性的一部電影,不該當作喜劇片來看,影片中展示的人與人之間的關係卻是值得咱們去深思。python

今天就跟着 湯老師 一塊兒來揭祕影片《一出好戲》,看看「這齣好戲」到底如何?json

咱們將使用Python抓取貓眼近10萬條評論數據,並對獲取到的數據進行分析,看看觀衆對這部電影的評價究竟如何?bash

整個數據分析的過程分爲四步:服務器

  1. 獲取數據
  2. 處理數據
  3. 存儲數據
  4. 數據可視化

1、獲取數據

1. 簡介

​ 本次獲取的是貓眼APP的評論數據,如圖所示:app

《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

經過分析發現貓眼APP的評論數據接口爲:echarts

http://m.maoyan.com/mmdb/comments/movie/1203084.json?_v_=yes&offset=0&startTime=2018-08-18%2022%3A25%3A03 dom

《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

​ 經過對評論數據進行分析,獲得以下信息:ide

  • 返回的是json格式數據函數

  • 1203084表示電影的專屬id;offset表示偏移量;startTime表示獲取評論的起始時間,從該時間向前取數據,即獲取最新的評論

  • cmts表示評論,每次獲取15條,offset偏移量是指每次獲取評論時的起始索引,向後取15條

  • hcmts表示熱門評論前10條

  • total表示總評論數

2. 代碼實現

​ 這裏先定義一個函數,用來根據指定url獲取數據,且只能獲取到指定的日期向前獲取到15條評論數據

# coding=utf-8
__author__ = '湯小洋'

from urllib import request
import json
import time
from datetime import datetime
from datetime import timedelta

# 獲取數據,根據url獲取
def get_data(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36'
    }
    req = request.Request(url, headers=headers)
    response = request.urlopen(req)
    if response.getcode() == 200:
        return response.read()
    return None

if __name__ == '__main__':
    html = get_data('http://m.maoyan.com/mmdb/comments/movie/1203084.json?_v_=yes&offset=0&startTime=2018-07-28%2022%3A25%3A03')
    print(html)

2、處理數據

對獲取的數據進行處理,轉換爲json

# 處理數據
def parse_data(html):
    data = json.loads(html)['cmts']  # 將str轉換爲json
    comments = []
    for item in data:
        comment = {
            'id': item['id'],
            'nickName': item['nickName'],
            'cityName': item['cityName'] if 'cityName' in item else '',  # 處理cityName不存在的狀況
            'content': item['content'].replace('\n', ' ', 10),  # 處理評論內容換行的狀況
            'score': item['score'],
            'startTime': item['startTime']
        }
        comments.append(comment)
    return comments

if __name__ == '__main__':
    html = get_data('http://m.maoyan.com/mmdb/comments/movie/1200486.json?_v_=yes&offset=0&startTime=2018-07-28%2022%3A25%3A03')
    comments = parse_data(html)
    print(comments)

3、存儲數據

​ 爲了可以獲取到全部評論數據,方法是:從當前時間開始,向前獲取數據,根據url每次獲取15條,而後獲得末尾評論的時間,從該時間繼續向前獲取數據,直到影片上映日期(2018-08-10)爲止,獲取這之間的全部數據。

# 存儲數據,存儲到文本文件
def save_to_txt():
    start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')  # 獲取當前時間,從當前時間向前獲取
    end_time = '2018-08-10 00:00:00'
    while start_time > end_time:
        url = 'http://m.maoyan.com/mmdb/comments/movie/1203084.json?_v_=yes&offset=0&startTime=' + start_time.replace(' ', '%20')
        html = None
        '''
            問題:當請求過於頻繁時,服務器會拒絕鏈接,其實是服務器的反爬蟲策略
            解決:1.在每一個請求間增長延時0.1秒,儘可能減小請求被拒絕
                 2.若是被拒絕,則0.5秒後重試
        '''
        try:
            html = get_data(url)
        except Exception as e:
            time.sleep(0.5)
            html = get_data(url)
        else:
            time.sleep(0.1)

        comments = parse_data(html)
        print(comments)
        start_time = comments[14]['startTime']  # 得到末尾評論的時間
        start_time = datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S') + timedelta(seconds=-1)  # 轉換爲datetime類型,減1秒,避免獲取到重複數據
        start_time = datetime.strftime(start_time, '%Y-%m-%d %H:%M:%S')  # 轉換爲str

        for item in comments:
            with open('comments.txt', 'a', encoding='utf-8') as f:
                f.write(str(item['id'])+','+item['nickName'] + ',' + item['cityName'] + ',' + item['content'] + ',' + str(item['score'])+ ',' + item['startTime'] + '\n')

if __name__ == '__main__':
    # html = get_data('http://m.maoyan.com/mmdb/comments/movie/1200486.json?_v_=yes&offset=0&startTime=2018-07-28%2022%3A25%3A03')
    # comments = parse_data(html)
    # print(comments)
    save_to_txt()

​ 有兩點須要說明:

  1. 服務器通常都有反爬蟲策略,當請求過於頻繁時,服務器會拒絕部分鏈接,我這裏是經過增長每一個請求間延時來解決,只是一種簡單的解決方案,還望各位看客理解包涵
  2. 根據數據量的多少,抓取數據所需時間會有所不一樣,我抓取的是2018-8-19到2018-8-10(上映當天)之間的數據,大概花了2個小時,共抓取約9.2萬條評論數據

《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

4、數據可視化

​ 這裏使用的是pyecharts,pyecharts是一個用於生成Echarts圖表的類庫,便於在Python中根據數據生成可視化的圖表。

​ Echarts是百度開源的一個數據可視化JS庫,主要用於數據可視化。

​ 參考:http://pyecharts.org/

# 安裝pyecharts
pip install pyecharts

​ pyecharts v0.3.2之後,pyecharts 將再也不自帶地圖 js 文件。如用戶須要用到地圖圖表,可自行安裝對應的地圖文件包。

# 安裝地圖文件包
pip install echarts-china-provinces-pypkg # 中國省、市、縣、區地圖
pip install echarts-china-cities-pypkg
pip install echarts-china-counties-pypkg
pip install echarts-china-misc-pypkg 
pip install echarts-countries-pypkg # 全球國家地圖
pip install echarts-united-kingdom-pypkg

1. 粉絲位置分佈

​ 代碼實現

# coding=utf-8
__author__ = '湯小洋'

# 導入Style類,用於定義樣式風格
from pyecharts import Style
# 導入Geo組件,用於生成地理座標類圖
from pyecharts import Geo
import json
# 導入Geo組件,用於生成柱狀圖
from pyecharts import Bar
# 導入Counter類,用於統計值出現的次數
from collections import Counter

# 數據可視化
def render():
    # 獲取評論中全部城市
    cities = []
    with open('comments.txt', mode='r', encoding='utf-8') as f:
        rows = f.readlines()
        for row in rows:
            city = row.split(',')[2]
            if city != '':  # 去掉城市名爲空的值
                cities.append(city)

    # 對城市數據和座標文件中的地名進行處理
    handle(cities)

    # 統計每一個城市出現的次數
    # data = []
    # for city in set(cities):
    #     data.append((city, cities.count(city)))
    data = Counter(cities).most_common()  # 使用Counter類統計出現的次數,並轉換爲元組列表
    # print(data)

    # 定義樣式
    style = Style(
        title_color='#fff',
        title_pos='center',
        width=1200,
        height=600,
        background_color='#404a59'
    )

    # 根據城市數據生成地理座標圖
    geo = Geo('《一出好戲》粉絲位置分佈', '數據來源:貓眼-湯小洋採集', **style.init_style)
    attr, value = geo.cast(data)
    geo.add('', attr, value, visual_range=[0, 3500],
            visual_text_color='#fff', symbol_size=15,
            is_visualmap=True, is_piecewise=True, visual_split_number=10)
    geo.render('粉絲位置分佈-地理座標圖.html')

    # 根據城市數據生成柱狀圖
    data_top20 = Counter(cities).most_common(20)  # 返回出現次數最多的20條
    bar = Bar('《一出好戲》粉絲來源排行TOP20', '數據來源:貓眼-湯小洋採集', title_pos='center', width=1200, height=600)
    attr, value = bar.cast(data_top20)
    bar.add('', attr, value, is_visualmap=True, visual_range=[0, 3500], visual_text_color='#fff', is_more_utils=True,
            is_label_show=True)
    bar.render('粉絲來源排行-柱狀圖.html')

​ 出現的問題:

  • 報錯:ValueError: No coordinate is specified for xxx(地名)

  • 緣由:pyecharts的座標文件中沒有該地名,其實是名稱不一致致使的,如數據中地名爲'達州',而座標文件中爲'達州市'

    座標文件所在路徑:項目/venv/lib/python3.6/site-packages/pyecharts/datasets/city_coordinates.json

  • 解決:修改座標文件,在原位置下複製個一樣的,而後修改下地名
{
  "達州市": [
    107.5,
    31.22
  ],
   "達州": [
    107.5,
    31.22
  ],
}

​ 不過因爲要修改的地名太多,上面的方法實在是麻煩,因此我定義了一個函數,用來處理地名數據找不到的問題

# 處理地名數據,解決座標文件中找不到地名的問題
def handle(cities):
    # print(len(cities), len(set(cities)))

    # 獲取座標文件中全部地名
    data = None
    with open(
            '/Users/wangbo/PycharmProjects/python-spider/venv/lib/python3.6/site-packages/pyecharts/datasets/city_coordinates.json',
            mode='r', encoding='utf-8') as f:
        data = json.loads(f.read())  # 將str轉換爲json

    # 循環判斷處理
    data_new = data.copy()  # 拷貝全部地名數據
    for city in set(cities):  # 使用set去重
        # 處理地名爲空的數據
        if city == '':
            while city in cities:
                cities.remove(city)
        count = 0
        for k in data.keys():
            count += 1
            if k == city:
                break
            if k.startswith(city):  # 處理簡寫的地名,如 達州市 簡寫爲 達州
                # print(k, city)
                data_new[city] = data[k]
                break
            if k.startswith(city[0:-1]) and len(city) >= 3:  # 處理行政變動的地名,如縣改區 或 縣改市等
                data_new[city] = data[k]
                break
        # 處理不存在的地名
        if count == len(data):
            while city in cities:
                cities.remove(city)

    # print(len(data), len(data_new))

    # 寫入覆蓋座標文件
    with open(
            '/Users/wangbo/PycharmProjects/python-spider/venv/lib/python3.6/site-packages/pyecharts/datasets/city_coordinates.json',
            mode='w', encoding='utf-8') as f:
        f.write(json.dumps(data_new, ensure_ascii=False))  # 將json轉換爲str

可視化結果:

粉絲人羣主要集中在沿海一帶

《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

從上圖能夠看出,《一出好戲》的觀影人羣主要集中在沿海一帶,這些地方經濟相對發達,城市人口基數龐大,極多的熒幕數量和座位、極高密度的排片場次,讓觀衆便捷觀影,活躍的觀衆評論也多,天然也就成爲票房的主要貢獻者。

《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

粉絲來源排名前20的城市依次爲:北京、深圳、上海、成都、武漢、廣州、西安、鄭州、重慶、南京、天津、瀋陽、長沙、東莞、哈爾濱、青島、杭州、合肥、大連、蘇州

電影消費是城市消費的一部分,從某種角度來看,能夠做爲考察一個城市購買力的指標。這些城市在近年的GDP排行中大都居上游,消費水平較高。

2. 詞雲圖

​ jieba是一個基於Python的分詞庫,完美支持中文分詞,功能強大

pip install jieba

​ Matplotlib是一個Python的2D繪圖庫,可以生成高質量的圖形,能夠快速生成繪圖、直方圖、功率譜、柱狀圖、偏差圖、散點圖等

pip install matplotlib

​ wordcloud是一個基於Python的詞雲生成類庫,能夠生成詞雲圖

pip install wordcloud

​ 代碼實現:

# coding=utf-8
__author__ = '湯小洋'

# 導入jieba模塊,用於中文分詞
import jieba
# 導入matplotlib,用於生成2D圖形
import matplotlib.pyplot as plt
# 導入wordcount,用於製做詞雲圖
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator

# 獲取全部評論
comments = []
with open('comments.txt', mode='r', encoding='utf-8') as f:
    rows = f.readlines()
    for row in rows:
        comment = row.split(',')[3]
        if comment != '':
            comments.append(comment)

# 設置分詞
comment_after_split = jieba.cut(str(comments), cut_all=False)  # 非全模式分詞,cut_all=false
words = ' '.join(comment_after_split)  # 以空格進行拼接
# print(words)

# 設置屏蔽詞
stopwords = STOPWORDS.copy()
stopwords.add('電影')
stopwords.add('一部')
stopwords.add('一個')
stopwords.add('沒有')
stopwords.add('什麼')
stopwords.add('有點')
stopwords.add('這部')
stopwords.add('這個')
stopwords.add('不是')
stopwords.add('真的')
stopwords.add('感受')
stopwords.add('以爲')
stopwords.add('仍是')
stopwords.add('可是')
stopwords.add('就是')
stopwords.add('一出')
stopwords.add('好戲')

# 導入背景圖
bg_image = plt.imread('bg.jpg')

# 設置詞雲參數,參數分別表示:畫布寬高、背景顏色、背景圖形狀、字體、屏蔽詞、最大詞的字體大小
wc = WordCloud(width=1024, height=768, background_color='white', mask=bg_image, font_path='STKAITI.TTF',
               stopwords=stopwords, max_font_size=400, random_state=50)
# 將分詞後數據傳入雲圖
wc.generate_from_text(words)
plt.imshow(wc)
plt.axis('off')  # 不顯示座標軸
plt.show()
# 保存結果到本地
wc.to_file('詞雲圖.jpg')

可視化結果:

整體評價很不錯

​ 對評論數據進行分詞後製做以下詞雲圖:

《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

​ 從詞雲圖中能夠看到:

  • 評論中屢次出現「能夠」、「好看」、「不錯」等熱詞,說明觀衆對《一出好戲》的整體評價仍是很不錯的
  • 同時對該影片中「張藝興」的「演技」也給予了很大的承認,我本人今天在觀看後也有同感,讓咱們看到了不同的張藝興,實力演員
  • 對於初次「導演」電影的「黃渤」,能拍出這樣的影片,粉絲們也是比較確定的,同時其自己就是票房的保障
  • 至於劇情方面,「現實」、「喜劇」、「搞笑」、「故事」等詞語,能看出這是一部反映現實的故事片,同時也兼具喜劇搞笑
  • 對於評論中出現的「通常」、「失望」等,這些粉絲或許是和我同樣,本覺得這是一部爆笑喜劇片,笑點應該會不少(畢竟在咱們心中,黃渤、王寶強等就是笑星),沒想到笑點並不不少,至少與期待的有差距,致使內心有落差的緣由吧^_^

《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

3. 評分星級

​ 代碼實現:

# coding=utf-8
__author__ = '湯小洋'

# 導入Pie組件,用於生成餅圖
from pyecharts import Pie

# 獲取評論中全部評分
rates = []
with open('comments.txt', mode='r', encoding='utf-8') as f:
    rows = f.readlines()
    for row in rows:
        rates.append(row.split(',')[4])
# print(rates)

# 定義星級,並統計各星級評分數量
attr = ['五星', '四星', '三星', '二星', '一星']
value = [
    rates.count('5') + rates.count('4.5'),
    rates.count('4') + rates.count('3.5'),
    rates.count('3') + rates.count('2.5'),
    rates.count('2') + rates.count('1.5'),
    rates.count('1') + rates.count('0.5')
]
# print(value)

pie = Pie('《一出好戲》評分星級比例', title_pos='center', width=900)
pie.add('7-17', attr, value, center=[75, 50], is_random=True,
        radius=[30, 75], rosetype='area',
        is_legend_show=False, is_label_show=True)
pie.render('評分.html')

可視化結果:

4、五星級影評合計高達83%

《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

​ 從圖中能夠看出,五星比例接近62%,四星比例爲21%,二者合計高達83%,可見口碑仍是至關不錯的,一星佔比不足6%

​ 《一出好戲》做爲黃渤第一次執導的做品,在拍攝過程當中導演渤哥對本身的要求也是很嚴格的,因此有這樣的成績,也是理所固然。

《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

附:今天看電影的票根 ^_^
《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一塊兒揭祕「這齣好戲」到底如何?

爬蟲案例對應的視頻課程:http://edu.51cto.com/course/14870.html

相關文章
相關標籤/搜索