票房和口碑稱霸國慶檔,用 Python 爬取貓眼評論區看看電影《我和我的家鄉》到底有多牛

  • 2020 年 10 月 5 日
  • 筆記

今年的國慶檔電影市場的表現還是比較強勢的,兩名主力《我和我的家鄉》和《姜子牙》起到了很好的帶頭作用。

《姜子牙》首日破 2 億,一舉刷新由《哪吒之魔童降世》保持的中國影市動畫電影首日票房紀錄,但因其後續口碑下滑,目前已被《我和我的家鄉》在口碑和票房上實現了全面的超越,如不出意外,《我和我的家鄉》將會是今年國慶檔的最大贏家。

從上圖中我們可以看出《我和我的家鄉》在貓眼上目前有 29.6 萬人評分,總體評分 9.3,可以說是一個相當不錯的成績了,本文我們爬取該片的貓眼電影評論,一起分析下這部影片評論區的內容。

爬取

首先,我們來爬取貓眼電影評論數據,因 PC 端只能看到貓眼上的幾條評論,所以我們要藉助 APP 介面來爬取,介面格式為://m.maoyan.com/mmdb/comments/movie/movieid.json?_v_=yes&offset=15&startTime=xxx,兩個參數說明如下:

  • movieid:網站中每部影片的唯一 id
  • startTime:當前頁面中第一條評論的時間,每頁共有 15 條評論

爬取的主要實現程式碼如下:

# 獲取頁面內容
def get_page(url):
    headers = {
        'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit'
                      '/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
        'accept': '*/*'
    }
    try:
        r = requests.get(url, headers=headers)
        r.raise_for_status()
        return r.text
    except requests.HTTPError as e:
        print(e)
    except requests.RequestException as e:
        print(e)
    except:
        print("出錯了")

# 解析介面返回數據
def parse_data(html):
    json_data = json.loads(html)['cmts']
    comments = []
    # 解析數據並存入數組
    try:
        for item in json_data:
            comment = []
            comment.append(item['nickName']) # 昵稱
            comment.append(item['cityName'] if 'cityName' in item else '') # 城市
            comment.append(item['content'].strip().replace('\n', '')) # 內容
            comment.append(item['score']) # 星級
            comment.append(item['startTime'])
            comment.append(item['time']) # 日期
            comment.append(item['approve']) # 贊數
            comment.append(item['reply']) # 回複數
            if 'gender' in item:
                comment.append(item['gender'])  # 性別
            comments.append(comment)
        return comments
    except Exception as e:
        print(comment)
        print(e)

# 保存數據,寫入 csv
def save_data(comments):
    filename = 'comments.csv'
    dataObject = pd.DataFrame(comments)
    dataObject.to_csv(filename, mode='a', index=False, sep=',', header=False, encoding='utf_8_sig')

本文我們爬取了 2w 條左右評論數據,並將爬取的數據保存到了 csv 文件中。

數據分析

評分星級

首先,我們看一下爬取數據中每個評分星級的比例情況,主要實現程式碼如下:

# 評分星級
rates = []
for s in df.iloc[:, 3]:
    rates.append(s)
sx = ["五星", "四星", "三星", "二星", "一星"]
sy = [
    str(rates.count(5.0) + rates.count(4.5)),
    str(rates.count(4.0) + rates.count(3.5)),
    str(rates.count(3.0) + rates.count(2.5)),
    str(rates.count(2.0) + rates.count(1.5)),
    str(rates.count(1.0) + rates.count(0.5))
]
(
    Pie(init_opts=opts.InitOpts(theme=ThemeType.CHALK, width='700px', height='400px'))
    .add("", list(zip(sx, sy)), radius=["40%", "70%"])
    .set_global_opts(title_opts=opts.TitleOpts(title="評分星級比例", subtitle="數據來源:貓眼電影", pos_left = "left"))
    .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{d}%", font_size=12))
).render_notebook()

效果如下:

從圖中我們可以看出:有接近 9 成的人給了該片 5 星,1、2、3 星總共佔比只有 5% 左右,說明該片的品質得到了大部分人的認可。

性別比例

我們接著看評論人中的性別情況,主要實現程式碼如下:

# 性別比例
rates = []
for s in df.iloc[:, 8]:
    if s != 1 and s != 2:
        s = 3
    rates.append(s)
gx = ["男", "女", "未知"]
gy = [
    rates.count(1),
    rates.count(2),
    rates.count(3)
]
(
    Pie(init_opts=opts.InitOpts(theme=ThemeType.CHALK, width="700px", height="400px"))
    .add("", list(zip(gx, gy)))
    .set_global_opts(title_opts=opts.TitleOpts(title="性別比例", subtitle="數據來源:貓眼電影", pos_left = "left"))
    .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{d}%", font_size=12))
).render_notebook()

效果如下:

通過上圖我們可以發現:大部分人是比較注重自己的隱私的,沒有顯示自己的性別,通過性別可見的數據,我們可以發現男人和女人在評論區的活躍程度比較接近,女人略高一些。

位置分布

我們再接著看評論人位置分布情況,先看下評論數量前 100 名的位置坐標情況,主要程式碼實現如下:

cities = []
for city in df.iloc[:, 1]:
    if city != "":
        cities.append(city)
data = Counter(cities).most_common(100)
gx1 = []
gy1 = []
for c in data:
    gx1.append(c[0])
    gy1.append(c[1])
geo = Geo(init_opts=opts.InitOpts(width="700px", height="400px", theme=ThemeType.DARK, bg_color="#404a59"))
(
    geo.add_schema(maptype="china", itemstyle_opts=opts.ItemStyleOpts(color="#323c48", border_color="#111"))
    .add("評論數量", list(zip(gx1, gy1)))
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(
       toolbox_opts=opts.ToolboxOpts,
       title_opts=opts.TitleOpts(title="位置分布地理坐標", subtitle="數據來源:貓眼電影", pos_left = "left"),
       visualmap_opts=opts.VisualMapOpts(max_=500, is_piecewise=True)
    )
).render_notebook()

效果如下:

下面再通過柱狀圖來展示一下評論數量前 15 名的城市,主要程式碼實現如下:

data_top15 = Counter(cities).most_common(15)
gx2 = []
gy2 = []
for c in data_top15:
    gx2.append(c[0])
    gy2.append(c[1])
(
    Bar(init_opts=opts.InitOpts(theme=ThemeType.CHALK, width="700px", height="400px"))
    .add_xaxis(gx2)
    .add_yaxis("", gy2)
    .set_global_opts(
        title_opts=opts.TitleOpts(title="城市來源 TOP15", subtitle="數據來源:貓眼電影", pos_left = "center")
    )
).render_notebook()

效果如下:

通過以上兩圖,我們可以直觀的看出哪些城市的人在該片下的評論數量多少,進而可以相應的了解到其對該片的感興趣程度。

時評數量

我們接著看 24 小時中的評論數量,主要程式碼實現如下:

times = df.iloc[:, 5]
hours = []
for t in times:
    hours.append(str(t[11:13]))
hdata = sorted(Counter(hours).most_common())
hx = []
hy = []
for c in hdata:
    hx.append(c[0])
    hy.append(c[1])
(
    Line(init_opts=opts.InitOpts(theme=ThemeType.CHALK, width="700px", height="400px"))
    .add_xaxis(hx)
    .add_yaxis("", hy, areastyle_opts=opts.AreaStyleOpts(opacity=0.5))
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(
        title_opts=opts.TitleOpts(title="24小時評論數量", subtitle="數據來源:貓眼電影", pos_left = "center")
    )
).render_notebook()

效果如下:

從圖中我們可以看出大家在下午 ~ 晚間活躍程度比較高,因 19 左右是晚飯時間,這個時間段評論數量下降也合乎常理。

主要演員

我們接著來看主要演員(包括其飾演的角色)在評論區中被提及的情況,主要程式碼實現如下:

cts_list = df.iloc[:, 2]
cts_str ="".join([str(i) for i in cts_list])
px = ["黃渤", "王寶強", "劉昊然", "葛優", "劉敏濤", "范偉", "張譯", "鄧超", "閆妮", "沈騰", "馬麗"]
py = [cts_str.count("黃渤") + cts_str.count("黃大寶"), cts_str.count("王寶強") + cts_str.count("老唐"),
      cts_str.count("劉昊然") + cts_str.count("小秦"), cts_str.count("葛優") + cts_str.count("張北京"),
      cts_str.count("劉敏濤") + cts_str.count("玲子"), cts_str.count("范偉") + cts_str.count("老范"),
      cts_str.count("張譯") + cts_str.count("姜前方"), cts_str.count("鄧超") + cts_str.count("喬樹林"),
      cts_str.count("閆妮") + cts_str.count("閆飛燕"), cts_str.count("沈騰") + cts_str.count("馬亮"),
      cts_str.count("馬麗") + cts_str.count("秋霞")]
(
    Bar(init_opts=opts.InitOpts(theme=ThemeType.CHALK, width="700px", height="400px"))
    .add_xaxis(px)
    .add_yaxis("", py)
    .set_global_opts(
        title_opts=opts.TitleOpts(title="主要演員及其飾演角色被提及次數", subtitle="數據來源:貓眼電影", pos_left = "center")
    )
).render_notebook()

效果如下:

從圖中我們可以看出主要演員在評論區出現次數的前三強為:沈騰、范偉和鄧超,進而說明這幾位演員的熱度比較高,在評論區引起了大家廣泛的熱議。

電影單元

我們接著看每個電影單元在評論區被提及的情況,主要程式碼實現如下:

mx = ["天上掉下個UFO", "北京好人", "最後一課", "回鄉之路", "神筆馬亮"]
my = [cts_str.count("天上掉下個UFO"), cts_str.count("北京好人"), cts_str.count("最後一課"), cts_str.count("回鄉之路"), cts_str.count("神筆馬亮")]
(
    Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK, width="700px", height="400px"))
    .add_xaxis(mx)
    .add_yaxis("", my)
    .set_global_opts(
        title_opts=opts.TitleOpts(title="電影單元被提及次數", subtitle="", pos_left = "center")
    )
).render_notebook()

效果如下:

從圖中我們可以看齣電影單元《最後一課》被提及的次數超過了其它幾個單元被提及次數的總和,進而可以看出其熱度比較高,引起了大家的共鳴,有點一枝獨秀的感覺。

詞雲展示

整體詞雲

首先我們來看一下整體評論的詞雲,程式碼實現如下:

cts_list = df.iloc[:, 2]
cts_str ="".join([str(i) for i in cts_list])
stylecloud.gen_stylecloud(text=cts_str, max_words=400,
                          collocations=False,
                          font_path="SIMLI.TTF",
                          icon_name="fas fa-home",
                          size=800,
                          output_name="total.png")
Image(filename="total.png")

效果如下:

從圖中我們可以直觀的看出:好看、很好看、值的一看、不錯、最後一課等被提及的次數比較多,說明大多數人對影片是比較滿意,電影單元最後一課熱度比較高、引起了很多人的共鳴。

熱評詞雲

最後,我們看一下熱門評論(點贊多、回復多的評論內容)的詞雲,程式碼實現如下:

hot_str = ""
for index, row in df.iterrows():
    content = row[2]
    support = row[6]
    reply = row[7]
    if(support > 30):
        hot_str += content
    elif (reply > 5):
        hot_str += content
stylecloud.gen_stylecloud(text=hot_str, max_words=200,
                          collocations=False,
                          font_path="SIMLI.TTF",
                          icon_name="fas fa-fire",
                          size=800,
                          output_name="hot.png")
Image(filename="hot.png")

效果如下:

這個熱門評論的畫風和之前有點不一樣了,最醒目(最大)的辭彙是:UFO、難看、電影倒是沒看、和對象開演前十分鐘分手了… 最後這個不多說了,大家自行體會吧~

因採集的評論數據有限,可能與實際情況存在一定的偏差,大家理性看待即可。

公眾號 Python小二 後台回復 201005 領取源碼。