Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

CDA數據分析師 出品

驚雷/通天修為/天塌地陷紫金錘

紫電/玄真火焰/九天玄劍驚天變

這看起來不著邊際的歌詞,配上簡單粗暴的蹦迪音樂。

最近,一首《驚雷》的喊麥歌曲在短視頻平臺火了,震驚了整個音樂圈。

但4月10日歌手楊坤卻在直播中批評《驚雷》“要歌沒歌,要旋律沒旋律,要節奏沒節奏,要律動沒律動”,評價其“難聽”、“俗氣”。

4月11日,MC六道以原唱者的身份對楊坤的指責做出回應表示,音樂沒有高低之分,稱《驚雷》現在比楊坤的任何一首歌都火。一時間更是把《驚雷》推上了風口浪尖。

那麼《驚雷》這首歌到底怎麼樣?都是哪些人在聽?今天我們就用Python來給你解讀。

01

拿下60億流量

喊麥歌曲《驚雷》火了!

說道喊麥,作為近年來一種新興的表演形式,其內容和表達方式則比較簡單和浮誇,主要形式是在網上下載一些伴奏(以電音伴奏為主),跟著伴奏以簡單的節奏和朗朗上口的押韻手法進行的語言表演。

更簡單的說法就是,演唱時不講究什麼技法,帶著伴奏對著麥喊就完事。比如之前爆火的《一人我飲酒醉》就是很具代表性的喊麥歌曲。

而喊麥歌曲也因為一味堆積看似沒有關聯的詞,鬧騰的電音,簡單粗暴的唱法等,讓大家各種吐槽。而在“全民抵制”喊麥的背景下,《驚雷》卻火了。

從今年3月起,以《驚雷》為BGM的短視頻在各大平臺上迅速走紅。截止到4月24日,在抖音的#驚雷#的標籤頁下顯示共有23w個視頻作品使用,產生64.1億次播放。

Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

一些網友更是跟風錄製了各種翻唱版本。溫柔版、方言版、戲腔版、小黃人版、種類之多,只有你想不到,沒有網友做不到。瞬間《驚雷》就成了今年度的網絡爆款神曲之一。在B站上搜索《驚雷》更是可以看到大量的相關視頻。

Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

我們對B站上《驚雷》的各類視頻進行整理分析發現:

Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

在3月底,《驚雷》就在B站小火了一把,總播放量突破50萬。接著到了4月12日,隨著楊坤和MC六道的“隔空互掐”,大量《驚雷》相關視頻如雨後春筍一般爆發出來,無論是音樂、遊戲、生活、影視和鬼畜各視頻分區產生的相關視頻突破300個,播放量更是水漲船高。

02

“精神小夥”專屬歌曲

都是哪些人在聽《驚雷》?

我們使用Python獲取並分析了網易雲音樂上,MC六道的這首《驚雷》相關的評論數據。

經過去重得到1534條樣本,從而來分析一下《驚雷》這首歌的用戶和評價信息。

先看到結論:

評論時間趨勢圖

Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

首先看到評論的時間,可以發現評論的高峰時間主要集中在:

  • 中午12-13點左右;
  • 下午5點之後的下班下課時間;
  • 以及傍晚睡前9-10點

看來主要的聽歌時間是在忙完工作的午休時,下班後的路上,以及睡前,刷著手機聽聽歌寫寫評論,也比較符合用戶的聽歌習慣。

評論用戶性別分佈

Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

聽歌的人群性別分佈是如何的呢?經過分析發現,男性佔比達到壓倒性的67.08%,女性佔比較少為16.43%,另外16.49%的用戶沒有標註性別。可見聽《驚雷》的更多是男性群體。

評論用戶年齡分佈

Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

分析發現,用戶大多集中在14-30歲之間,以20歲左右居多,除去異常和虛假年齡之外,這個年齡分佈也符合網易雲用戶的年齡段。

評論用戶地區分佈

Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

從城市分佈圖中可以看出,評論用戶涵蓋了全國各大省份,其中廣東的評論用戶排名第一,其次是山東、河北、河南等省份。

Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

根據網易雲曾發佈的音樂數據,北上廣深等發達地帶的用戶對小眾音樂情有獨鍾,這些城市聚集了大量的小眾音樂用戶,其中廣東也是聚集了眾多熱愛電音的用戶,堪稱“最電音省份”。

同時我們查詢了2019年全國各省份的人口排名,排名前三的省份是:廣東、山東、河南,這個結果也與分佈圖較為吻合,果然還是人多力量大。

評論情感正負分佈

那麼評論中大家對《驚雷》更多是稱讚還是吐槽呢?接著我們對評論區的留言進行了情感分析,使用的是百度的API。

我們定義了一個函數獲取情感評分正向和負向的概率值,值介於[0,1]之前,越接近1,情感越偏向於積極,反之則越消極。

Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

通過評論情感得分分佈圖,可以發現:

在1534條數據中,有780條數據評分分值在[0,0.05]之間,佔比50.08%,有一半以上的用戶對這首歌表達了非常厭惡的情緒。我們還看到,有227個樣本的評分在0.95以上,屬於非常正向,這些正向評論真的正向嗎?

我們不妨看幾條這些評論:

Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

比如這一條:

謝謝,這首‘歌’我笑吐了

明顯是屬於負向的情緒,但是因為正向的關鍵詞比較多,百度的情感分析程序給了0.97分,所以可以看出這裡的正向評分也是有誤差。

還有這一條:

突然感覺楊坤老師有點偉大

這首歌雖然是讚揚楊坤老師,但是放到這裡是表達貶義,但是程序並沒有判斷出來,間接說明程序還是沒有人聰明啊(擬合能力不足+漢語語境情況複雜)。

所以實際上大部分評論帶著反諷的口吻,我們可以大膽推斷,這首歌的負向情緒佔比至少上升10~15%個百分點。

評論詞雲分佈:

Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

通過文本分析,可以看出大家對這首歌的評論集中對楊坤和MC六道的討論上,吐槽點主要集中在關於歌曲的“難聽”、“俗氣”、"抄襲"等。同時也表達了對於“喊麥”和"音樂"的討論上。

03

教你用Python分析

網易雲音樂《驚雷》的評論

我們使用Python獲取並分析了網易雲音樂上《驚雷2020》相關的評論數據並進行了以下部分處理和分析,整個分析過程分為以下幾個步驟:

  1. 數據獲取
  2. 數據讀入與數據預處理
  3. 數據分析和可視化

01 數據獲取

此次爬蟲部分主要是調用官方API,本次用到的API主要是:


http://music.163.com/api/v1/resource/comments/R_SO_4_{歌曲ID}?limit={每頁限制數量}&offset={評論數總偏移}

參數說明如下:

{歌曲ID}:歌曲ID

limit:限制每頁獲取的數據條數

offset:翻頁參數偏移量,offset需要是limit的倍數

返回的數據格式為json,通過此接口目前每天獲取的數據量限制是1000條,代碼思路如下:

  1. 先獲取一頁的數據,並封裝成解析函數parse_one_page
  2. 變化offset參數,循環構建URL,並調用解析函數

具體代碼如下:

<code># 導入庫
import requests
import json
import time
import pandas as pd

def parse_one_page(comment_url):
    """
    功能:給定一頁的評論接口,獲取一頁的數據。
    """
    # 添加headers
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36'
    }

    # 發起請求
    r = requests.get(comment_url, headers=headers)

    # 解析數據
    comment_data = r.json()['comments']

    # 獲取用戶ID
    user_id = [i['user']['userId'] for i in comment_data]
    # 獲取用戶暱稱
    nick_name = [i['user']['nickname'] for i in comment_data]
    # 獲取評論ID
    comment_id = [i['commentId'] for i in comment_data]
    # 獲取評論內容
    content = [i['content'] for i in comment_data]
    # 獲取評論時間
    content_time = [i['time'] for i in comment_data]
    # 獲取點贊
    liked_Count = [i['likedCount'] for i in comment_data]

    df_one = pd.DataFrame({
        'user_id': user_id,
        'nick_name': nick_name,
        'comment_id': comment_id,
        'content': content,
        'content_time': content_time,
        'liked_Count': liked_Count
    })

    return df_one


def get_all_page(song_id):
    """
    功能:獲取100頁短評:目前接口一天最多獲取數據量
    """
    df_all = pd.DataFrame()

    for i in range(101):  # 最多100頁
        url = 'http://music.163.com/api/v1/resource/comments/R_SO_4_{}?limit=10&offset={}'.format(song_id, i*10)
        # 調用函數
        df = parse_one_page(comment_url=url)
        # 循環追加
        df_all = df_all.append(df, ignore_index=True)
        # 打印進度
        print('我正在獲取第{}頁的信息'.format(i + 1))
        # 休眠一秒
        time.sleep(1)

    return df_all

if __name__ == '__main__':
    # 驚雷
    song_id = '1431580747'
    # 運行函數
    df_jl = get_all_page(song_id) 
獲取到的數據如下所示,此次我們一共獲取了兩天的數據,經過去重得到1534條樣本,來分析一下《驚雷》這首歌的用戶和評價信息。

獲取的數據集主要包含了以下的信息:評論ID、用戶ID、用戶暱稱、用戶評論、評論時間、評論點贊。根據用戶ID可以獲取評論用戶相關信息,此處暫不做贅述。/<code> 
<code># 提取正負概率
positive_prob = [i[0]['positive_prob'] for i in score_list]
negative_prob = [i[0]['negative_prob'] for i in score_list]

# 增加列
df_comment['positive_prob'] = positive_prob
df_comment['negative_prob'] = negative_prob

# 添加正向1 負向-1標籤
df_comment['score_label'] = df_comment['positive_prob'].apply(lambda x:1 if x>0.5 else -1) 
df_comment.head() /<code>
Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?

02 數據讀入與數據預處理

此處,我們將對獲取的評論數據集進行以下的處理以方便後續的分析:

  1. 讀入數據和數據合併,去除重複值
  2. 評論時間:將評論時間轉換為標準時間
  3. 用戶評論:使用jieba分詞對評論數據進行分詞處理。

代碼實現如下:

讀入數據、合併、去重

<code># 輸入API Key和Secret Key
ak = '你的API Key'
sk = '你的Secret Key'

host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={}&client_secret={}'.format(ak, sk)

# 發起請求
r = requests.post(host) 
# 獲取token
token = r.json()['access_token']

def get_sentiment_score(text):
    """
    輸入文本,返回情感傾向得分
    """
    url = 'https://aip.baidubce.com/rpc/2.0/nlp/v1/sentiment_classify?charset=UTF-8&access_token={}'.format(token)
    data = {
        'text': text
    } 
    data = json.dumps(data)
    try:
        res = requests.post(url, data=data, timeout=3)
        items_score = res.json()['items']
    except Exception as e:
        time.sleep(1) 
        res = requests.post(url, data=data, timeout=3)
        items_score = res.json()['items']
    return items_score/<code>
<code># 獲取情感傾向分值並存入列表
score_list = [] 

step = 0
for i in df_comment['content']:
    score = get_sentiment_score(i)
    # 打印進度
    step += 1
    print('我正在獲取第{}個評分'.format(step), end='\r') 
    score_list.append(score) /<code>

評論時間處理

<code># 提取正負概率
positive_prob = [i[0]['positive_prob'] for i in score_list]
negative_prob = [i[0]['negative_prob'] for i in score_list]

# 增加列
df_comment['positive_prob'] = positive_prob
df_comment['negative_prob'] = negative_prob

# 添加正向1 負向-1標籤
df_comment['score_label'] = df_comment['positive_prob'].apply(lambda x:1 if x>0.5 else -1) 
df_comment.head() /<code>

03 使用百度API進行情感分析

情感分析是NLP的重要部分。這裡我們使用百度的API,來進行情感分析,經測試這個API接口結果相對比較準確。我們定義了一個函數獲取情感評分正向和負向的概率值。返回結果解釋:以正向概率positive_prob為例,值介於[0,1]之前,越接近1,情感越偏向於積極。

代碼和結果如下:

<code># 異常值處理
df_comment['content'] = df_comment['content'].replace('⚰️', '黑人抬棺') /<code>
<code># 輸入API Key和Secret Key
ak = '你的API Key'
sk = '你的Secret Key'

host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={}&client_secret={}'.format(ak, sk)

# 發起請求
r = requests.post(host) 
# 獲取token
token = r.json()['access_token']

def get_sentiment_score(text):
    """
    輸入文本,返回情感傾向得分
    """
    url = 'https://aip.baidubce.com/rpc/2.0/nlp/v1/sentiment_classify?charset=UTF-8&access_token={}'.format(token)
    data = {
        'text': text
    } 
    data = json.dumps(data)
    try:
        res = requests.post(url, data=data, timeout=3)
        items_score = res.json()['items']
    except Exception as e:
        time.sleep(1) 
        res = requests.post(url, data=data, timeout=3)
        items_score = res.json()['items']
    return items_score/<code>
<code># 獲取情感傾向分值並存入列表
score_list = [] 

step = 0
for i in df_comment['content']:
    score = get_sentiment_score(i)
    # 打印進度
    step += 1
    print('我正在獲取第{}個評分'.format(step), end='\r') 
    score_list.append(score) /<code>

最後提取正負向的概率,並添加標籤。將positive_prob>0.5定義為正向。

<code># 提取正負概率
positive_prob = [i[0]['positive_prob'] for i in score_list]
negative_prob = [i[0]['negative_prob'] for i in score_list]

# 增加列
df_comment['positive_prob'] = positive_prob
df_comment['negative_prob'] = negative_prob

# 添加正向1 負向-1標籤
df_comment['score_label'] = df_comment['positive_prob'].apply(lambda x:1 if x>0.5 else -1) 
df_comment.head() /<code>


Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?


04 數據可視化


我們將進行以下的數據可視化


  1. 評論數時間(按小時)分佈
  2. 評論用戶性別佔比
  3. 評論用戶年齡分佈
  4. 評論用戶地區分佈
  5. 評論情感得分正負向標籤佔比分析-基於百度自然語言處理API
  6. 評論情感得分分佈
  7. 評論詞雲分析


評論數時間(按小時)分佈

<code>age_num = pd.Series(df_user.age.value_counts())
# 刪除異常值
age_num = age_num.drop(['未知',-5, -9, 0, 1, 6, 7]) 
age_num = pd.DataFrame(age_num).reset_index().rename({'index':'age', 'age':'num'}, axis=1)

# 分箱
age_num['age_cut'] = pd.cut(age_num.age, bins=[10,15,20,25,30,35]) 

# 分組彙總
age_cut_num = age_num.groupby('age_cut')['num'].sum()


from pyecharts.charts import Bar

# 繪製柱形圖
bar1 = Bar(init_opts=opts.InitOpts(width='1350px', height='750px'))
bar1.add_xaxis(age_cut_num.index.astype('str').tolist())
bar1.add_yaxis("數量", age_cut_num.values.tolist(), category_gap='20%')
bar1.set_global_opts(title_opts=opts.TitleOpts(title="評論用戶年齡分佈"),
                     visualmap_opts=opts.VisualMapOpts(max_=180),
                     toolbox_opts=opts.ToolboxOpts())
bar1.render()/<code> 


經過統計,此次數據採樣日期來自4.22~4.24日。


通過評論時間按小時分佈圖可以看出,評論數在一天當中從5點開始一路攀升,一天有三個小高峰:13點-17點-21點。


評論用戶性別佔比

<code># 計算佔比
gender_perc = df_user['gender'].value_counts()  / df_user['gender'].value_counts() .sum()
gender_perc = np.round(gender_perc*100,2)

from pyecharts.charts import Pie

# 繪製餅圖
pie1 = Pie(init_opts=opts.InitOpts(width='1350px', height='750px'))
pie1.add("",
         [*zip(gender_perc.index, gender_perc.values)],
         radius=["40%","65%"])
pie1.set_global_opts(title_opts=opts.TitleOpts(title='評論用戶性別分佈'),
                     legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%"),
                     toolbox_opts=opts.ToolboxOpts()) 
pie1.set_series_opts(label_opts=opts.LabelOpts(formatter="{c}%"))
pie1.set_colors(['#D7655A', '#FFAF34', '#3B7BA9', '#EF9050', '#6FB27C'])
pie1.render() /<code>


通過評論用戶性別分佈圖可以看出,在評論用戶中男性用戶佔到了67.08%。


評論用戶年齡分佈

<code>age_num = pd.Series(df_user.age.value_counts())
# 刪除異常值
age_num = age_num.drop(['未知',-5, -9, 0, 1, 6, 7]) 
age_num = pd.DataFrame(age_num).reset_index().rename({'index':'age', 'age':'num'}, axis=1)

# 分箱
age_num['age_cut'] = pd.cut(age_num.age, bins=[10,15,20,25,30,35]) 

# 分組彙總
age_cut_num = age_num.groupby('age_cut')['num'].sum()


from pyecharts.charts import Bar

# 繪製柱形圖
bar1 = Bar(init_opts=opts.InitOpts(width='1350px', height='750px'))
bar1.add_xaxis(age_cut_num.index.astype('str').tolist())
bar1.add_yaxis("數量", age_cut_num.values.tolist(), category_gap='20%')
bar1.set_global_opts(title_opts=opts.TitleOpts(title="評論用戶年齡分佈"),
                     visualmap_opts=opts.VisualMapOpts(max_=180),
                     toolbox_opts=opts.ToolboxOpts())
bar1.render()/<code>


用戶年齡分佈圖可以看出,用戶大多集中在14-30歲之間,以20歲左右居多,除去異常和虛假年齡之外,這個年齡分佈也符合網易雲用戶的年齡段。


評論用戶城市分佈Top10

<code>province_num = df_user.province_name.value_counts()
province_num.index = province_num.index.str[:2]
province_top10 = province_num[:10]

# 柱形圖
bar2 = Bar(init_opts=opts.InitOpts(width='1350px', height='750px'))
bar2.add_xaxis(province_top10.index.tolist())
bar2.add_yaxis("城市", province_top10.values.tolist())
bar2.set_global_opts(title_opts=opts.TitleOpts(title="評論者Top10城市分佈"),
                     visualmap_opts=opts.VisualMapOpts(max_=120),
                     toolbox_opts=opts.ToolboxOpts())
bar2.render() /<code>


<code>from pyecharts.charts import Geo
from pyecharts.globals import ChartType

# 地圖
geo1 = Geo(init_opts=opts.InitOpts(width='1350px', height='750px'))
geo1.add_schema(maptype='china')
geo1.add("", [list(z) for z in zip(province_num.index.tolist(), province_num.values.tolist())], 
         type_=ChartType.EFFECT_SCATTER,
         blur_size=15) 
geo1.set_global_opts(title_opts=opts.TitleOpts(title='評論者國內城市分佈'), 
                     visualmap_opts=opts.VisualMapOpts(max_=120))
geo1.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
geo1.render()  /<code>


<code># 地圖
map1 = Map(init_opts=opts.InitOpts(width='1350px', height='750px')) 
map1.add("", [list(z) for z in zip(province_num.index.tolist(), province_num.values.tolist())],
         maptype='china')
map1.set_global_opts(title_opts=opts.TitleOpts(title='評論者國內城市分佈'),
                     visualmap_opts=opts.VisualMapOpts(max_=120),
                     toolbox_opts=opts.ToolboxOpts())
map1.render() /<code>


城市分佈圖中可以看出,評論用戶涵蓋了全國各大省份,其中廣東的評論用戶排名第一。


評論情感得分正負向標籤佔比分析

<code>label_num = df_comment.score_label.value_counts() / df_comment.score_label.value_counts().sum()
label_perc = np.round(label_num,3) 
label_perc.index = ['負向', '正向'] 
label_perc/<code>


<code>負向    0.701
正向    0.299
Name: score_label, dtype: float64/<code>


<code># 繪製餅圖
pie2 = Pie(init_opts=opts.InitOpts(width='1350px', height='750px'))
pie2.add("",
         [*zip(label_perc.index, label_perc.values)],
         radius=["40%","65%"])
pie2.set_global_opts(title_opts=opts.TitleOpts(title='評論情感標籤正負向分佈'),
                     legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%"),
                     toolbox_opts=opts.ToolboxOpts()) 
pie2.set_series_opts(label_opts=opts.LabelOpts(formatter="{c}%"))
pie2.set_colors(['#3B7BA9', '#EF9050'])
pie2.render() /<code> 


通過分佈圖可以看出,評論內容中70%左右的內容表達了負向的情緒,說明對於《驚雷》這首喊麥的歌曲,大眾主要持批判的觀點。


情感評論得分分佈

<code># 定義分隔區間
bins = [0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5,
       0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0]
positive_num = pd.cut(df_comment.positive_prob, bins).value_counts()
positive_num = positive_num.sort_index()
# 柱形圖
bar3 = Bar(init_opts=opts.InitOpts(width='1350px', height='750px'))
bar3.add_xaxis(positive_num.index.astype('str').tolist())
bar3.add_yaxis("", positive_num.values.tolist(), category_gap='5%')
bar3.set_global_opts(title_opts=opts.TitleOpts(title="評論情感得分"), 
                     visualmap_opts=opts.VisualMapOpts(max_=500),
                     toolbox_opts=opts.ToolboxOpts()
                    )
bar3.render() /<code>


通過評論情感得分分佈圖,可以發現,在1534條數據中,有780條數據評分分值在[0,0.05]之間,佔比50.08%。


評論詞雲分析


此處數據處理主要使用jieba分詞,步驟暫略。

<code>from pyecharts.charts import WordCloud
from pyecharts.globals import SymbolType

word1 = WordCloud(init_opts=opts.InitOpts(width='1350px', height='750px'))
word1.add("", [*zip(key_words.words, key_words.num)],
          word_size_range=[20, 200],
          shape=SymbolType.DIAMOND)
word1.set_global_opts(title_opts=opts.TitleOpts('網易雲音樂關於驚雷評論詞雲'),
                      toolbox_opts=opts.ToolboxOpts(),
                     )
word1.render() /<code>
Python爬蟲告訴你:拿下60億流量的《驚雷》都是哪些人在聽?


分享到:


相關文章: