Python告訴你:從《入海》到《消愁》毛不易的歌裏都在唱些什麼?

【導語】:今天我們來聊聊——B站聯合毛不易發佈的畢業季主題曲《入海》,以及背後不一樣的毛不易。Python技術部分請看第三部分

 

Show me data,用數據說話!今天我們聊一聊 毛不易的《入海》,沒錯,還是那個B站,在520這個既浪漫且有營銷價值的一天又「搞事情」了。

 

5月20日, B站聯合毛不易發佈畢業季主題曲《入海》。這首歌主題是“獻給即將或已經畢業的人們”,歌曲MV中以主人公畢業的時候爲原點,追憶過去,並用大量篇幅展現普通人畢業後的社會生活。

 

這首歌一經發布就在B站引爆了話題點,截止到5月24日在B站播放量達到了800萬+,收穫了5.2萬彈幕,最高全站日排行1名。

 

 

今天我們就帶你來解讀這首《入海》,以及背後不一樣的毛不易。

 

01、毛不易的歌裏,都喜歡唱些什麼?

 

毛不易,本名王維家。本來畢業於杭州師範大學護理專業的他一直有個歌手夢。在2017年,參加騰訊視頻選秀音樂娛樂節目《明日之子》,獲得全國總決賽冠軍,從而正式進入演藝圈。誰又能想到最後拿到冠軍是這個長相平平,沒有什麼優勢,甚至有點害羞憨厚的毛不易了。

 

隨着《消愁》《像我這樣的人》等歌曲的大火,毛不易這個名字也被越來越多的人知曉。同時在今年鵝廠的女團選秀節目《創造營2020》中,毛不易更是以導師的身份加入,呆萌的毛老師這次也收穫了不少的粉絲。

 

聽着《消愁》裏的“一杯敬朝陽,一杯敬月光“,大概是因爲才華,毛不易在這個年紀能寫出人生的無奈和糾葛,這是一種大的勇氣。

 

 

那麼毛不易的歌裏都在唱些什麼呢?下面讓我們來盤一盤:

 

我們分析整理了毛不易在網易雲音樂的歌曲,一共83首,歌詞字數加起來45577字,我們用Python對這些歌詞進行分析。

 

歌曲時長分佈

 

首先在歌曲時長方面,時長爲4-5分鐘的最多高達43.9%,3-4分鐘爲29.27%,2-3分鐘的爲13.41%。要知道一般歌曲時長多爲3分鐘左右,看來毛不易的歌時長還是偏長的。

 

歌曲正向情感得分

我們使用boson庫對每首歌的歌詞的情感進行打分,分數介於0~100分,高於50分爲積極,分數越高,積極傾向性越高。從分佈圖可以看出,在83首歌曲中,大部分的歌曲正向積極情感爲主。

 

毛不易最喜歡的詞TOP15

毛不易最喜歡的歌裏最喜歡用哪些詞呢?我們分析整理得出了歌詞中出現頻率最高的TOP15。可以看到"等待"、"生活"、"時光"等詞出現頻率最高,位列前三。

 

"慢慢"、"遇見"、"江水"、"角落"等比較文藝的詞也上榜了。有意思的是"有錢"出現頻率也較高,位列第四。

 

02、《入海》全站日排名第一,這首獻給畢業季的歌好在哪兒?

 

我們使用Python獲取並分析了B站上《入海》這首MV的評論數據,經過去重之後得到19099條樣本,下面讓我們看到評論的具體分析。

 

評論用戶性別佔比

 

首先,在評論用戶性別佔比方面,男性用戶佔比略高,男性用戶佔比54.69%,女性用戶佔比45.31%。

 

評論用戶客戶端分佈

 

那麼看《入海》的用戶在看視頻時都用的什麼移動設備呢?經過分析發現,用iphone的用戶佔了很大的比例,遠超Andrio系統的用戶。第三位是使用ipad的用戶。

 

 

評論用戶等級分佈

 

同時我們知道,b站上用戶因爲參與程度等因素,等級從0-6分佈,數字越大等級越高。在《入海》這首歌的評論用戶上,評論中5級的佔比最高爲36.1%,其次是4級佔比26.31%,6級佔比僅爲3.24%,這也是因爲畢竟要成爲六級大佬實在太難了。

各時段評論人數

 

在評論時間段方面,《入海》是在5月20日 8:30發佈的,在發佈後評論的人數越來越多,在12點左右評論達到最高峯,這個時段共有2萬7千餘人進行評論,遠高於其他時段,之後隨着時間推移評論人數也越來越少,趨於平緩。

 

評論關鍵詞TOP15

 

在評論中大家說得最多的是什麼呢?

 

 

經過分析整理可以看到,"畢業"是提到最多的詞,其次第二位是"後浪",畢竟作爲同樣聚焦在年輕人身上的話題,這次的《入海》很容易讓大家聯繫到5月4日B站發佈的《後浪》視頻。

同時,"快樂"、"入海"、"大哭"等詞也被頻頻提到。

 

03、Python分析:B站《入海》評論數據

 

我們使用Python獲取並分析了B站上《入海》這首MV的評論數據。經過去重之後得到19099條樣本,來分析一下這周MV的用戶的評論信息。整個分析流程分爲以下幾步:

 

  1. 數據獲取
  2. 數據整理
  3. 數據可視化

 

數據獲取

 

在獲取視頻評論之前,我們首要做的就是分析其網頁結構,尋找目標數據,也就是我們要評論的數據在哪裏。

 

經過抓包分析,在network-json選項卡下,很容易找到了數據傳輸的地址,經過分析和精簡,目標數據的url鏈接爲:

 

https://api.bilibili.com/x/v2/reply?&type=1&oid=795637027&pn=1

 

其中oid是視頻的專屬oid,pn是頁面數。

 

由上圖可看出,其評論數據是以json數據形式存在於網頁端的,目前顯示的頁數是976頁,每頁20條評論,追評數據暫時不做抓取。

 

接下來,就爬取思路很明確,從第一頁的JSON文件開始,爬完20條評論,循環pn頁數,直到爬完所有的評論數據。

 

代碼如下:

# 導入所需包
import requests
import json
import pandas as pd
import time


def get_bili_comment_one(url):
    """
    功能:定義函數,獲取一頁的信息
    """
    # 添加headers
    headers = {
        'Host': 'api.bilibili.com',
        'Referer': 'https://www.bilibili.com/video/BV1YZ4y1j7s5',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'
    }

    # 添加cookies
    cookies = {
        "cookie": "複製您的瀏覽器cookie信息"
    }

    # 發起請求
    try:
        r = requests.get(url, headers=headers, cookies=cookies, timeout=3)
    except Exception as e:
        print(e)
        r = requests.get(url, headers=headers, cookies=cookies, timeout=3)

    # 解析爲字典
    r_json = json.loads(r.text)

    # 提取信息
    replies_data = r_json['data']['replies']

    # 用戶名
    user_name = [i['member'].get('uname') for i in replies_data]
    # 性別
    sex = [i['member'].get('sex') for i in replies_data]
    # 簽名
    sign = [i['member'].get('sign') for i in replies_data]
    # 用戶等級
    current_level = [i['member']['level_info'].get('current_level') for i in replies_data]
    # 評論內容
    content = [i['content'].get('message') for i in replies_data]
    # 用戶設備
    device = [i['content'].get('device') for i in replies_data]
    # 評論時間
    content_time = [i.get('ctime') for i in replies_data]
    # 回覆數
    reply_count = [i['rcount'] for i in replies_data]

    # 存儲數據
    df = pd.DataFrame({
        'user_name': user_name,
        'sex': sex,
        'sign': sign,
        'current_level': current_level,
        'content': content,
        'device': device,
        'content_time': content_time,
        'reply_count': reply_count
    })

    return df


def get_bili_comment_all(oid, num):
    """
    功能:定義函數,獲取B站視頻指定頁評論信息
    """
    # 循環構建URL
    df_all = pd.DataFrame()

    for page_num in range(1, num):
        try:
            # 構建URL
            url = 'https://api.bilibili.com/x/v2/reply?&pn={}&type=1&oid={}&sort=2'.format(page_num, oid)
            # 調用函數
            df = get_bili_comment_one(url)
            # 判斷
            if df.shape[0] == 0:
                break
            else:
                # 循環追加
                df_all = df_all.append(df, ignore_index=True)
                # 打印進度
                print('我正在獲取第{}頁的信息'.format(page_num))
        except:
            break

    # 休眠一秒
    time.sleep(0.5)

    return df_all


# 《入海》bilibili X 毛不易 | 躍入人海,各有風雨燦爛
df = get_bili_comment_all(oid='795637027', num=973)

獲取到的數據以DataFrame的形式存儲,格式如下:

# 讀入數據
df.head()  

 

 

數據集有19099個樣本,8個字段,字段名稱爲:用戶名、用戶性別、用戶簽名、用戶等級、用戶評論、設備名稱、評論時間、點贊數。

 

df.info() 

 

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 19099 entries, 0 to 19098
Data columns (total 8 columns):
user_name        19099 non-null object
sex              19099 non-null object
sign             9896 non-null object
current_level    19099 non-null int64
content          19099 non-null object
device           4159 non-null object
content_time     19099 non-null int64
reply_count      19099 non-null int64
dtypes: int64(3), object(5)
memory usage: 1.2+ MB

 

數據整理

 

此處我們主要對以上獲取的數據集進行部分清洗工作以方便後續的處理:

 

  1. 重複值處理
  2. 類型轉化
  3. 時間戳數據處理
  4. 評論數據jieba分詞處理-(代碼暫略)

 

# 導入包
import numpy as np 
import pandas as pd

# 讀入數據
df = pd.read_excel('../data/B站評論數據-入海5.23.xlsx')

# 去重
df = df.drop_duplicates()

# 轉換類型
df['content'] = [str(i) for i in df.content] 

# 定義轉換時間
def transform_timestamp(time_second):
    timeArray = time.localtime(time_second)
    otherStyleTime = time.strftime('%Y-%m-%d %H:%M:%S', timeArray) 
    return otherStyleTime

# 提取時間
df['content_time'] = df['content_time'].apply(lambda x:transform_timestamp(x)) 

 

數據可視化分析

 

此處我們將進行以下部分的數據可視化分析,首先導入所需包,其中pyecharts用於繪製動態圖形,stylecloud用於繪製詞雲圖,關鍵代碼如下:

from pyecharts.charts import Bar, Pie, Line, WordCloud, Page
from pyecharts import options as opts 
from pyecharts.globals import SymbolType

import stylecloud
from IPython.display import Image

 

評論性別佔比

# 總體評分分佈
sex_num = df['sex'].value_counts()
sex_num.drop('保密', inplace=True) 

# 繪製餅圖
data_pair =  [list(z) for z in zip(sex_num.index.tolist(), sex_num.values.tolist())]

# 繪製餅圖
pie1 = Pie(init_opts=opts.InitOpts(width='1350px', height='750px'))
pie1.add('', data_pair, radius=['35%', '60%'])
pie1.set_global_opts(title_opts=opts.TitleOpts(title='評論用戶性別佔比'), 
                     legend_opts=opts.LegendOpts(orient='vertical', pos_top='15%', pos_left='2%'))
pie1.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{d}%"))
pie1.set_colors(['#EF9050', '#3B7BA9', '#6FB27C'])
pie1.render()

 

用戶客戶端分佈

device_num = df.device.value_counts(ascending=True) 

# 柱形圖
bar1 = Bar(init_opts=opts.InitOpts(width='1350px', height='750px'))
bar1.add_xaxis(device_num.index.tolist())
bar1.add_yaxis('', device_num.values.tolist(), 
               label_opts=opts.LabelOpts(position='right'))
bar1.set_global_opts(title_opts=opts.TitleOpts(title='評論客戶端分佈'), 
                     visualmap_opts=opts.VisualMapOpts(max_=3000))
bar1.reversal_axis()
bar1.render() 

 

用戶等級分佈

# 用戶等級
level_num = df.current_level.value_counts()

data_pair2 =  [list(z) for z in zip(['LV' + i for i in level_num.index.astype('str').tolist()] , level_num.values.tolist())]

# 繪製餅圖
pie2 = Pie(init_opts=opts.InitOpts(width='1350px', height='750px'))
pie2.add('', data_pair=data_pair2, radius=['35%', '60%'])
pie2.set_global_opts(title_opts=opts.TitleOpts(title='評論用戶等級分佈'), 
                     legend_opts=opts.LegendOpts(orient='vertical', pos_top='15%', pos_left='2%'))
pie2.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{c}({d}%)"))
pie2.set_colors(['#EF9050', '#3B7BA9', '#6FB27C', '#FFAF34'])
pie2.render()

 

評論時間走勢圖

# 時間數據處理
df['time'] = df.content_time.str.split('-').str[1] + '-' + df.content_time.str.split('-').str[2]
df['time'] = df.time.str.split(':').str[0]
time_num = df.time.value_counts().sort_index()

# 產生數據
x1_line1 = time_num.index.values.astype('str').tolist()
y1_line1 = time_num.values.tolist() 

# 繪製面積圖
line1 = Line(init_opts=opts.InitOpts(width='1350px', height='750px'))
line1.add_xaxis(x1_line1)
line1.add_yaxis('', y1_line1, areastyle_opts=opts.AreaStyleOpts(opacity=0.3),
                markpoint_opts=opts.MarkPointOpts(data=[
                    opts.MarkPointItem(type_='max', name='最大值')
                ])) 
line1.set_global_opts(title_opts=opts.TitleOpts('各個時段評論人數'), 
                      xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate='30'))
                     ) 
line1.set_series_opts(label_opts=opts.LabelOpts(is_show=False), 
                      axisline_opts=opts.AxisLineOpts()
                     )
line1.render()

 

評論詞雲圖

import stylecloud
from IPython.display import Image # 用於在jupyter lab中顯示本地圖片

stylecloud.gen_stylecloud(text=' '.join(word_num),  # txt需要傳入str格式 
                          collocations=False,
                          font_path=r'‪C:\Windows\Fonts\msyh.ttc',
                          icon_name='fas fa-graduation-cap',
                          size=768,
                          output_name='B站評論詞雲圖.png')
Image(filename='B站評論詞雲圖.png') 

 

CDA數據分析師 出品  

作者:Mika

數據:真達  

後期:澤龍、Mika

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章