《用python 玩转数据》项目——B站弹幕数据分析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《用python 玩转数据》项目——B站弹幕数据分析相关的知识,希望对你有一定的参考价值。

1. 背景

在视频网站上,一边看视频一边发弹幕已经是网友的习惯。在B站上有很多种类的视频,也聚集了各种爱好的网友。本项目,就是对B站弹幕数据进行分析。选取分析的对象是B站上点播量过1.4亿的一部剧《Re:从零开始的异世界生活》

2.       算法

分两部分:

 第一部分:

2.1     在《Re:从零开始的异世界生活》的首页面,找到共25集的所有对应播放链接和剧名的格式,获取每一集的播放链接,并保存。

2.2     从每一集的播放页面中,通过正则re获取它的cid号,获得cid号后,就可用于获取弹幕文件。由于是动态页面,所以使用了selenium库的PhantomJS()方法。

2.3     因为b站需要通过格式为:https://comment.bilibili.com/dmroll,{time},{cid}的链接获取弹幕历史文件,所以要获取30天内的弹幕历史,就要计算出最近30天的时间戳。最后将组装好的url 保存到history_danmu_url.txt 文件。

2.4     当弹幕文件的url准备完成后,就可以通过静态页面的获取方法requests.get(url) 获取弹幕页面。所有的弹幕历史格式:<d p="533.67199707031,1,25,41194,1498943949,0,7edeebe9,3511616609">刀还是没有枪快</d>

2.5     p这个字段里面的内容:(资料来自百度搜索)

0,1,25,16777215,1312863760,0,eff85771,42759017中几个逗号分割的数据

第一个参数是弹幕出现的时间以秒数为单位。

第二个参数是弹幕的模式1..3 滚动弹幕 4底端弹幕 5顶端弹幕 6.逆向弹幕 7精准定位 8高级弹幕

第三个参数是字号, 12非常小,16特小,18,25,36,45很大,64特别大

第四个参数是字体的颜色HTML颜色的十进制为准

第五个参数是Unix格式的时间戳。基准时间为 1970-1-1 08:00:00

第六个参数是弹幕池 0普通池 1字幕池 2特殊池【目前特殊池为高级弹幕专用】

第七个参数是发送者的ID,用于“屏蔽此弹幕的发送者”功能

第八个参数是弹幕在弹幕数据库中rowID 用于“历史弹幕”功能。

2.6     逐个弹幕历史文件爬取,将内容一集的30天的弹幕历史,以[‘dtTime‘, ‘danmu_model‘, ‘font‘, ‘rgb‘, ‘stamp‘,‘danmu_chi‘, ‘userID‘, ‘rowID‘, ‘message‘, ‘episode‘] 的格式保存到d1.csvd2.csvd3.csv……的文件中

2.7     除了将30天的所有历史弹幕保存在一起外,爬虫程序,还将每一集视频,在B站的最新弹幕历史文件的内容单独保存在文件名格式为now1.csvnow2.csv……的文件中。获取最新弹幕历史文件的链接格式是:https://comment.bilibili.com/{cid}.xml,它们已经被保存在”comment.txt”文件。


第二部分:

2.8     保存了所有的数据后,对数据进行处理:先读取.csv文件,然后进行可视化分析:

2.8.1  每集弹幕总量的变化图

逐个读入弹幕历史文件:d1.csv,d2.csv,……经过去重后,统计出每集的弹幕总量:     

        data = pd.read_csv(item.strip(),encoding=‘gbk‘)

统计每一集,近30天,弹幕总量,保存在字典:{1323233 2212121 .......}

episode_comment_dic[data.loc[1,‘episode‘]] = every_episode_comment(data)

2.8.2  发弹幕总量top5用户

  

                     a.统计每一集,30天内的弹幕数量,依据弹幕数量,把用户排序,每一集排序后的结果是一个DataFrame

 结果的大致结构:user_sort_dic = {1: DataFrame1, 2:DataFrame2, ......,25: DataFrame25}

user_sort_dic[data.loc[1, ‘episode‘]] =every_episode_usersort(data)                                                                                         

b.把经过排序统计处理后的所有DataFrame 进行concat。然后就可以统计所有用户在30天内,对25集视频发送弹幕的数量。最后对用户排序。最终结果:d4_alldanmu_sort 是一个DataFrame 变量,将用户按弹幕数,降序排列。

d3_all_user = (pd.concat([item for k, itemin user_sort_dic.items()]))

d3_all_user[‘userID‘] = d3_all_user.index

aSer =d3_all_user.groupby(‘userID‘).episode.sum()

d4_alldanmu_sort =pd.DataFrame(aSer).sort_values(by=‘episode‘, ascending=False)

2.8.3  用户发弹幕长度分布

   统计发送弹幕的字符串长度。

        danmu_length_dic[data.loc[1,‘episode‘]] = static_danmu_length(data)

2.8.4  用户发弹幕数量分布

    统计一集,用户发送弹幕数量的百分比分布图。

d_tmp = user_sort_dic[i] #统计用户排名时已经有数据了

                  every_episode_danmu_pie(d_tmp, i)

2.8.5  每集弹幕密度变化图

   弹幕都有一个时间参数,代表了在视频的什么时间发了弹幕。可以统计出在相同时间参数发出的弹幕量,然后再画出“时间--弹幕”折线图,就可以看到弹幕量的变化了。

2.8.6  每集热词画出词云

   对每一集的弹幕文本进行分析。先用jieba词库进行分词,然后逐行对弹幕进行词频统计,最后用WordCloud 画出词云图。


3.       安装

使用的是anaconda的环境。所以直接在anaconda里进行安装:

pip install -ihttps://pypi.tuna.tsinghua.edu.cn/simple jieba

conda –c  https://conda.anaconda.org/conda-forge  wordecloud #词云只支持到python3.4



4.       统计结果

    4. 1  每集弹幕总量变化

技术分享

 4.2  发送弹幕总量top5 用户

   技术分享

4.3  用户发送弹幕长度分布

    技术分享

4.4  用户发送弹幕数量分布

   技术分享


4.5  每集弹幕密度分布图

    技术分享

4.6  每集的词云

   技术分享



5.        结果分析

   通过以上的图表数据可以看出用户的弹幕的一些行为。

         5.1   25集剧里,第一集和最后一集,弹幕数量是最多的,这和其他剧的开头和结尾两部的一样。中间的18集也获得了很多的弹幕数,原来是在那集里剧情出现了很大的变化,吸引了大家的讨论。

        5.2   统计了25部剧,用户ID356ed98的用户共发送了580多条弹幕,算是超级粉丝了。

        5.3   通过弹幕数量和长度的分布,可以看出:

   绝大部分用户只会发送2条以内的弹幕。

   参与弹幕讨论的用户以10个字符以内的短语为主。

5.4    统计每一集的弹幕密度,可以通过用户观看时的讨论,大致确定视频的精彩点。

5.5    通过词云图,可以大致看出用户的分布。例如第一集里重温作为热词显示里。说明现在有很多用户是会多次观看这部剧的。


6. 参考代码

6.1 爬虫部分:

    

# -*- coding: utf-8 -*-
"""
Created on Mon Jul 10 16:34:27 2017

@author: ahchpr

filename: re_zero_bili.py
"""

import requests, csv, re, time
from bs4 import BeautifulSoup as BS
from selenium import webdriver
import datetime
from multiprocessing import Pool
import sys   



# Re:从零开始的异世界生活 的总剧情首页
first_url = ‘https://bangumi.bilibili.com/anime/3461‘ 
headers = {‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)‘}
one_url = ‘https://bangumi.bilibili.com/anime/3461/play#86298‘
#history_danmu_url = ‘https://comment.bilibili.com/dmroll,time,cid‘
#now_danmu_url = ‘https://comment.bilibili.com/{}.xml‘.format(danmu_id)

def get_danmu_id(url):
    MyDriver = webdriver.PhantomJS()
    MyDriver.get(url)
    time.sleep(3)
    danmu_id = re.findall(r‘cid=(\d+)&‘, MyDriver.page_source)[0]
    return (danmu_id)
    
    

def sele_get_first(url):
    MyDriver = webdriver.PhantomJS()
    MyDriver.get(url)
    time.sleep(5)
    response = MyDriver.page_source.encode(‘utf-8‘)
    page = response.decode(‘utf-8‘)
    return (page)
   

def sele_get_re_list(page):
    pattern = re.compile(‘<a.*?href="(.*?)" title="(.*?)" target.*? class="v1-complete-text"><div class=‘)
    abstract = re.findall(pattern, page)
    return (abstract)


def request_get_comment(url):
    headers = {‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)‘}
    episode = url.split(" ")[0]
    url = url.split(" ")[1].strip()
    response = requests.get(url=url, headers=headers)

    soup = BS(response.text, ‘lxml‘)
    result = soup.find_all(‘d‘)
    if  len(result) == 0:
        return (result)
    
    all_list = []
    for item in result:
#        danmu_list.append(item.get(‘p‘).split(",").append(item.string))
        danmu_list = item.get(‘p‘).split(",")
        danmu_list.append(item.string)
#        danmu_list[0] = sec_to_str(danmu_list[0])
#        danmu_list[4] = time.ctime(eval(danmu_list[4]))
        danmu_list.append(episode)
#        print(danmu_list)
        all_list.append(danmu_list)
    return (all_list)
        
        
  
"""将秒转换成固定格式 "hh:mm:ss"
"""      
def sec_to_str(seconds):
    seconds = eval(seconds)
    m, s = divmod(seconds, 60)
    h, m = divmod(m, 60)
    dtEventTime = "%02d:%02d:%02d" % (h, m, s)
    return (dtEventTime)
    

"""计算最近30天的每天的时间戳,并返回,用于获取历史弹幕
"""
def time_to_stamp():
    today = datetime.date.today()    
    end_day = datetime.datetime(today.year, today.month, today.day)
    start_day = end_day - datetime.timedelta(30)
    gap_day_sum = 30
    stamp_list = []
    for i in range(1, gap_day_sum):
        tmp = start_day + datetime.timedelta(i)
        stamp_list.append(int(time.mktime(tmp.timetuple())))
        
    return (stamp_list)


def csv_write(tablelist, num):
    tableheader = [‘dtTime‘, ‘danmu_model‘, ‘font‘, ‘rgb‘, ‘stamp‘, ‘danmu_chi‘, ‘userID‘, ‘rowID‘, ‘message‘, ‘episode‘]
    file_name = "now{}.csv".format(num)
    print(file_name)
    with open(file_name, ‘w‘, newline=‘‘, errors=‘ignore‘) as fd:
        writer = csv.writer(fd)
        writer.writerow(tableheader)
        for row in tablelist:
            writer.writerow(row)
            
    
if __name__ == "__main__":
    sys.setrecursionlimit(1000000) 
    """爬取首页,获取共25话 《re:从零开始的异世界生活》 的播放连接
    """
    page = sele_get_first(first_url)
    re_list = sele_get_re_list(page)
#    print(len(re_list))
    
    
    """以字典的形式保存例如:
    {‘1‘: [‘初始的终结与结束的开始‘, ‘https://bangumi.bilibili.com/anime/3461/play#85754‘],...}
    """
    re_dict = {}
    for item in re_list:
        re_dict[item[1].split(" ")[0]] = [item[1].split(" ")[1], item[0]]
#    print(re_dict)
    
    """获取每一话的播放连接,保存成列表
    """
    re_url_list = []
    for i in range(1, len(re_dict)+1):
        re_url_list.append( re_dict[str(i)][1] )
        
    """利用进程池,获取每一话的弹幕文件连接,
    """
    re_danmu_id_list = []
    pool = Pool(14)
    re_danmu_id_list = pool.map(get_danmu_id, re_url_list)
    pool.close()    
    pool.join()
    re_danmu_id_dict = {}
    for n, p in enumerate(re_danmu_id_list):
        re_danmu_id_dict[str(n+1)] = p
    
    
    """将25话剧集的各自的最新的弹幕文件连接保存到一个文档 comment.txt,按照剧集的顺序保存
    """
    with open(‘comment.txt‘, ‘w‘) as fd:
        for i in range(len(re_danmu_id_list)):   
            fd.write(‘{} https://comment.bilibili.com/{}.xml\n‘.format(i+1, re_danmu_id_list[i]))
            
    
    history_danmu_url_list = []   
    stamp_list = time_to_stamp()
    for i in range(1, len(re_danmu_id_list)+1):
        for stamp in stamp_list :
            history_danmu_url = ‘{} https://comment.bilibili.com/dmroll,{},{}‘.format(i, stamp, re_danmu_id_dict[str(i)])
            history_danmu_url_list.append(history_danmu_url)
        history_danmu_url_list.append(‘{} https://comment.bilibili.com/{}.xml‘.format(i, re_danmu_id_dict[str(i)]))
   
    with open(‘history_danmu_url.txt‘, ‘w‘) as fd:
        for line in history_danmu_url_list:
            fd.write("{}\n".format(line))
            
        
    all_list = []

    ‘‘‘把每一集的弹幕文件链接,按照集数,整理到一个字典,
    ‘‘‘
    url_dict ={}
    with open ("history_danmu_url.txt", ‘r‘) as fd:
        url_whole = fd.readlines()
        print(len(url_whole))
        for i in range(1, len(re_danmu_id_list)+1):
            url_dict[str(i)] = [line for line in url_whole if int(line.split(" ")[0])==i]
    print (len(url_dict))
    
    ‘‘‘按照集数,取出弹幕链接,进行爬虫,获取弹幕记录,并保存到.csv 文件
    ‘‘‘
    for i in range(1, len(url_dict)+1):
        n = 0
        tmp_to_get_url = url_dict[(str(i))]
        file_name = "d{}.csv".format(i)
        tableheader = [‘dtTime‘, ‘danmu_model‘, ‘font‘, ‘rgb‘, ‘stamp‘, ‘danmu_chi‘, ‘userID‘, ‘rowID‘, ‘message‘, ‘episode‘]
        with open(file_name, ‘a‘,  newline=‘‘, errors=‘ignore‘) as fd:
            writer = csv.writer(fd)
            writer.writerow(tableheader)
            for url in tmp_to_get_url :        
                all_list = request_get_comment(url)
                if all_list:
                    for row in all_list:
                        writer.writerow(row)
                print("\n\n\n\n\n")
                n = n+1
                print(n)
                del (all_list)
        del tmp_to_get_url
        
        
        
        
    """获取保存最新历史弹幕文件
    """
    now_danmu_all = {}
    with open (‘comment.txt‘, ‘r‘) as fd:
        for url in fd:
            now_danmu_all[int(url.strip().split(" ")[0])] = request_get_comment(url)

    for num, data in now_danmu_all.items():
        csv_write(data, num)


6.2 数据统计可视化分析部分:

  

# -*- coding: utf-8 -*-
"""
Created on Wed Jul 12 08:43:04 2017

@author: ahchpr

filename: static_danmu_comment.py

"""

import pandas as pd
import matplotlib.pyplot as plt
import os
from scipy.misc import imread
from wordcloud import WordCloud
import jieba
import jieba.posseg as pseg
import math



def danmu_compress_plot(data, num):
    plt.cla()
    plt.xlabel(u"视频时间", fontproperties=‘SimHei‘)
    plt.ylabel(u"弹幕量", fontproperties=‘SimHei‘)
    plt.title(u‘第{}集_时间轴弹幕变化‘.format(num), fontproperties=‘SimHei‘)
    
    keys = [item for item in data.index ]
   
    values = [item for item in data.dtTime]
 
    """弹幕密度折线图
    """
    plt.plot(keys, values)
    plt.show()


def danmu_compress(data):
    df = data.drop_duplicates()
    dd = df.copy()
#    round_dic = {}
#    向下取“整秒数”
#    round_dic[‘dtTime_new‘] = [math.floor(item) for item in dd.dtTime]
    dd[‘dtTime_new‘] = [math.floor(item) for item in dd.dtTime]
#    dd.sort_values(by=‘dtTime_new‘, inplace=True)
#    print (dd.iloc[1:200, [6, 0, 10]])
    dc = dd.groupby(‘dtTime_new‘).count()
    result = dc.sort_index()
    return (result)

    ‘‘‘result  大概的结构:只写出了一列参考,其中dtTime就是在0秒开始时的弹幕数量
                   dtTime    
    dtTime_new                           
    0               75   
    1               37               
    2               34               
    ‘‘‘

def extract_words(data, num):
    
    df = data.drop_duplicates()
    dd = df.copy()
    message_list = [str(item) for item in dd.message]
    
    stop_words = set(line.strip() for line in open(‘stopwords.txt‘, encoding=‘utf-8‘))
    
    newslist = []
    for subject in message_list:
        if subject.isspace():
            continue
        # segment words line by line
        word_list = pseg.cut(subject)
        for word, flag in word_list:
            if not word in stop_words and flag == ‘n‘:
                newslist.append(word)

    d = os.path.dirname(__file__)
    mask_image = imread(os.path.join(d, "qiaodan.png"))
    content = ‘ ‘.join(newslist)
    wordcloud = WordCloud(font_path=‘simhei.ttf‘, background_color="grey", mask=mask_image, max_words=40).generate(content)
    
    # Display the generated image:
    file_name = u"第{}集_热词云.jpg".format(num)
    plt.imshow(wordcloud)
    plt.axis("off")
    plt.title(file_name, fontproperties=‘SimHei‘)
    wordcloud.to_file(file_name)
    plt.show()
    plt.cla()
    plt.close()


def static_danmu_length(data):
    df = data.drop_duplicates()
    dd = df.copy()
    dd[‘message_len‘] = [len(str(item)) for item in df.message] #统计每条弹幕的长度
    d1 = dd.loc[:, [‘userID‘, ‘message‘, ‘message_len‘, ‘episode‘]]
    dr = d1.copy()
    return (dr)

def every_episode_usersort(data):
    df = data.drop_duplicates()
    dd = df.groupby("userID").count()
    user_sort = dd.sort_values(by=‘episode‘, ascending=False).loc[:,[‘episode‘]]
    return (user_sort)


def every_episode_user(data):
    ‘‘‘30天内共有多少用户发弹幕
    ‘‘‘
    df = data.drop_duplicates()
    dd = df.groupby("userID").count()
    user_sum = len(dd)
    return (user_sum)

  
    
def every_episode_comment(data):
    ‘‘‘30天内有多少弹幕发出
    ‘‘‘
    df = data.drop_duplicates()
    danmu_sum = len(df)
    return (danmu_sum)


def top_user_danmu(data):
    plt.cla()
    ing = range(5)
    x = data.head(5).episode.index
    y = data.head(5).episode.values
    plt.xticks(ing, x, rotation=30)
    plt.xlabel(u"用户ID", fontproperties=‘SimHei‘)
    plt.ylabel(u"发弹幕数量", fontproperties=‘SimHei‘)
    plt.title(u"发弹幕数top5用户",fontproperties=‘SimHei‘)
    plt.bar(ing, y)
    plt.show()

   
def every_episode_comment_change(episode_comment_dic):      
    plt.cla()
    plt.xlabel(u"剧集", fontproperties=‘SimHei‘)
    plt.ylabel(u"弹幕量", fontproperties=‘SimHei‘)
    plt.title(u‘每集弹幕总量变化‘, fontproperties=‘SimHei‘)
    keys = range(1, len(episode_comment_dic)+1)
    values = []
    for i in keys:
        values.append(episode_comment_dic[i])
       
    """每一集弹幕总量的折线变化图
    """
    plt.plot(keys, values)
    plt.show()
    
    
def every_episode_danmu_pie(d_tmp, num):
    
    a1 = float(len(d_tmp[(d_tmp.episode>=1) & (d_tmp.episode<=2)]))
    a2 = len(d_tmp[(d_tmp.episode>=3) & (d_tmp.episode<=8)])
    a3 = len(d_tmp[(d_tmp.episode>=9) & (d_tmp.episode<=20)])
    a4 = len(d_tmp[(d_tmp.episode>=21) ])
     
    s =  a1 + a2 + a3 + a4 
    s = float(s)
    li = [a1 , a2 , a3 , a4  ]
    xp = []
    for i in li:
        i = float(i)
        if i<=0:
            t = 0
            xp.append(t)
        else:
            t = (i/s*100)
            xp.append(t)
    
    plt.rcParams[‘font.sans-serif‘]=[‘SimHei‘] #用来正常显示中文标签
    plt.rcParams[‘axes.unicode_minus‘]=False #用来正常显示负号
    
    plt.figure(figsize=(6,9))
    labels = [u‘1-2条‘, u‘2-8条‘, u‘9-20条‘, u‘21条以上‘ ]
    sizes = xp
    colors = [‘red‘, ‘yellow‘, ‘gray‘, ‘lightskyblue‘]
    explodes = [0 , 0, 0, 0.6]
    
    plt.axis(‘equal‘)
    plt.title(u‘第{}集_用户发送弹幕数量百分比分布图‘.format(num))
    plt.pie(sizes,  labels=labels,explode=explodes, colors=colors, labeldistance=0.5,
            autopct = ‘%2.2f%%‘, startangle = 90, pctdistance = 0.8)
    
    plt.show()
    plt.close()
    
    
def danmu_length_pie(d_tmp, num):   
    a1 = float(len(d_tmp[(d_tmp.message_len>=1) & (d_tmp.message_len<=4)]))
    a2 = float(len(d_tmp[(d_tmp.message_len>=5) & (d_tmp.message_len<=10)]))
    a3 = float(len(d_tmp[(d_tmp.message_len>=11) & (d_tmp.message_len<=15)]))
    a4 = float(len(d_tmp[(d_tmp.message_len>=16) ]))
    s =  a1 + a2 + a3 + a4 
    s = float(s)
    li = [a1 , a2 , a3 , a4  ]
    xp = []
    for i in li:
        i = float(i)
        if i<=0:
            t = 0
            xp.append(t)
        else:
            t = (i/s*100)
            xp.append(t)
    
    plt.rcParams[‘font.sans-serif‘]=[‘SimHei‘] #用来正常显示中文标签
    plt.rcParams[‘axes.unicode_minus‘]=False #用来正常显示负号
    
    plt.figure(figsize=(6,9))
    labels = [u‘1-4个‘, u‘5-10个‘, u‘11-15个‘, u‘16个以上‘ ]
    sizes = xp
    colors = [‘red‘, ‘yellow‘, ‘gray‘, ‘lightskyblue‘]
    explodes = [0 , 0, 0, 0.09]
    plt.axis(‘equal‘)
    plt.title(u‘第{}集_用户发送弹幕长度百分比分布图‘.format(num))
    plt.pie(sizes,  labels=labels, colors=colors, explode=explodes, labeldistance=0.5,
            autopct = ‘%2.2f%%‘, startangle = 90, pctdistance = 0.8)
    
    plt.show()
    plt.close()


#秒转换成时间
def sec_to_str(seconds):
    seconds = eval(seconds)
    m, s = divmod(seconds, 60)
    h, m = divmod(m, 60)
    length_time = "%02d:%02d:%02d" % (h, m, s)
    return (length_time)

    
if __name__ == "__main__":            
    
    path = os.getcwd()
    path_list = []
    for i in range(1, 26):
        path_list.append(path + "\\d{}.csv".format(i))
        
    episode_comment_dic = {}
    user_sum_dic = {}
    user_sort_dic = {}
    danmu_length_dic = {}
    reyun_data_dic = {}
    for item in path_list:
        ‘‘‘读取csv数据源文件,每一集的近30天弹幕都保存在一个csv文件
        ‘‘‘
        data = pd.read_csv(item.strip(), encoding=‘gbk‘)
        
        ‘‘‘统计每一集,近30天,弹幕总量,保存在字典:{1:323233, 2:212121, .......}
        ‘‘‘
        episode_comment_dic[data.loc[1, ‘episode‘]] = every_episode_comment(data)
        
        ‘‘‘统计每一集,近30天,共有多少用户发了弹幕,保存在字典:{1:3737, 2:34234,......}
        ‘‘‘
        user_sum_dic[data.loc[1, ‘episode‘]] = every_episode_user(data)
        
        ‘‘‘统计每一集,30天内的弹幕数量,依据弹幕数量,把用户排序,每一集排序后的结果是一个DataFrame,
           user_sort_dic = {1: DataFrame1, 2:DataFrame2, ......, 25: DataFrame25}
        ‘‘‘
        user_sort_dic[data.loc[1, ‘episode‘]] = every_episode_usersort(data)
        
        
        ‘‘‘统计发送弹幕的字符串长度
        ‘‘‘
        danmu_length_dic[data.loc[1, ‘episode‘]] = static_danmu_length(data)
        
        ‘‘‘统计每一集的分词,热词,词云
        ‘‘‘
        reyun_data_dic[data.loc[1, ‘episode‘]] = data.copy()
        

        ‘‘‘统计每一集,近30天的弹幕量,视频里的每一秒的弹幕数量,弹幕密度
        ‘‘‘
#        danmu_compress_dic[data.loc[1, ‘episode‘]] =  danmu_compress(data)
    
        
        del data
        
        
    print(episode_comment_dic)
    print(user_sum_dic)
    
    ‘‘‘把经过排序统计处理后的所有DataFrame 进行concat。然后就可以统计所有用户在30天内,对25集视频
       发送弹幕的数量。最后对用户排序。最终结果:
       d4_alldanmu_sort 是一个DataFrame 变量,将用户按弹幕数,降序排列。
    ‘‘‘
    d3_all_user = (pd.concat([item for k, item in user_sort_dic.items()]))
    d3_all_user[‘userID‘] = d3_all_user.index
    aSer = d3_all_user.groupby(‘userID‘).episode.sum()
    d4_alldanmu_sort = pd.DataFrame(aSer).sort_values(by=‘episode‘, ascending=False)
    
    
    ‘‘‘绘制折线图:25集视频,近30天每集弹幕总数
    ‘‘‘
    every_episode_comment_change(episode_comment_dic)
    
    
    ‘‘‘柱状图:25集视频,近30天,所有用户中,发弹幕数量最多的5个用户
    ‘‘‘
    top_user_danmu(d4_alldanmu_sort)
    
    ‘‘‘统计一集,用户发送弹幕数量的百分比分布图
    ‘‘‘
    for i in range(1, len(user_sort_dic)+1):
        d_tmp = user_sort_dic[i]
        every_episode_danmu_pie(d_tmp, i)
        del d_tmp
        
   
    ‘‘‘统计用户发送弹幕的长度分布百分比
    ‘‘‘
    for i in range(1, len(user_sort_dic)+1):
        d_tmp = danmu_length_dic[i]
        danmu_length_pie(d_tmp, i)
        del d_tmp
     
 
    ‘‘‘分析弹幕密度,使用当前最新的历史弹幕文件分析
    ‘‘‘
    now_danmu_list = []
    for i in range(1, 26):
        now_danmu_list.append(path + "\\now{}.csv".format(i))
    
    danmu_compress_dic = {}
    for item in now_danmu_list:
        data = pd.read_csv(item.strip(), encoding=‘gbk‘)
        danmu_compress_dic[data.loc[1, ‘episode‘]] =  danmu_compress(data)

    for num, data in danmu_compress_dic.items():
        danmu_compress_plot(data, num)
        
    """绘制热词云图,热词的运行时间太久了,先关闭
    """
    for num, data in reyun_data_dic.items():
        extract_words(data, num)


本文出自 “dayAndNight” 博客,请务必保留此出处http://hellocjq.blog.51cto.com/11336969/1947252

以上是关于《用python 玩转数据》项目——B站弹幕数据分析的主要内容,如果未能解决你的问题,请参考以下文章

震惊!一菜鸟竟用pyecharts分析B站弹幕作出这么靓的图~

Android弹幕实现:基于B站弹幕开源系统

Android弹幕实现:基于B站弹幕开源系统

Android弹幕实现:基于B站弹幕开源系统-重构

实现B站弹幕很难么?这个开源项目了解一下

B站弹幕系统架构——GOIM解读