精华内容
下载资源
问答
  • 弹幕数据分析
    2020-07-29 17:38:43

    腾讯弹幕数据分析

    数据读入
    In [1]:

    导入库

    import os
    import jieba
    import numpy as np
    import pandas as pd

    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 # 用于在jupyter lab中显示本地图

    In [2]:

    读入数据

    data_list = os.listdir(’…/data/’)

    df_all = pd.DataFrame()

    for i in data_list:
    # 判断
    if i.split(’.’)[-1] == ‘csv’:
    print(i)
    df_one = pd.read_csv(f’…/data/{i}’, engine=‘python’, encoding=‘utf-8’, index_col=0)
    df_all = df_all.append(df_one, ignore_index=False)

    print(df_all.shape)

    第10集.csv
    第11集.csv
    第12集.csv
    第13集.csv
    第14集.csv
    第15集.csv
    第1集.csv
    第2集.csv
    第3集.csv
    第4集.csv
    第5集.csv
    第6集.csv
    第7集.csv
    第8集.csv
    第9集.csv
    (271049, 7)
    In [3]:

    df_all.info()

    <class ‘pandas.core.frame.DataFrame’>
    Int64Index: 271049 entries, 0 to 17637
    Data columns (total 7 columns):

    Column Non-Null Count Dtype


    0 episodes 271049 non-null int64
    1 comment_id 271049 non-null int64
    2 oper_name 139035 non-null object
    3 vip_degree 271049 non-null int64
    4 content 271049 non-null object
    5 time_point 271049 non-null int64
    6 up_count 271049 non-null int64
    dtypes: int64(5), object(2)
    memory usage: 16.5+ MB
    In [4]:

    df_all.head()

    Out[4]:

    episodes
    comment_id
    oper_name
    vip_degree
    content
    time_point
    up_count
    0
    10
    6691339556383867223
    NaN
    5
    1
    27
    0
    1
    10
    6691340141707381348
    沉尘
    2
    王漫妮 : 来了来了
    28
    1
    2
    10
    6691340663373931124
    NaN
    5
    钟晓芹 : 第一来了
    29
    1
    3
    10
    6691340707249533722
    NaN
    2
    哈哈哈哈来了
    26
    0
    4
    10
    6691340998716925826
    NaN
    0
    每天等更新
    27
    3

    数据预处理
    In [5]:

    提取数据

    pattern = r’(王漫妮\s*|钟晓芹\s*|顾佳\s*|陈屿\s*|许幻山\s*|飒飒*\s|浪浪*\s):.*’
    df_all[‘danmu_role’] = df_all[‘content’].str.extract(pattern)[0].str.strip()
    df_all.head()

    Out[5]:

    episodes
    comment_id
    oper_name
    vip_degree
    content
    time_point
    up_count
    danmu_role
    0
    10
    6691339556383867223
    NaN
    5
    1
    27
    0
    NaN
    1
    10
    6691340141707381348
    沉尘
    2
    王漫妮 : 来了来了
    28
    1
    王漫妮
    2
    10
    6691340663373931124
    NaN
    5
    钟晓芹 : 第一来了
    29
    1
    钟晓芹
    3
    10
    6691340707249533722
    NaN
    2
    哈哈哈哈来了
    26
    0
    NaN
    4
    10
    6691340998716925826
    NaN
    0
    每天等更新
    27
    3
    NaN
    In [6]:

    def transform_name(x):
    if x==‘王漫妮’ or x==‘顾佳’ or x==‘钟晓芹’ or x==‘陈屿’ or x==‘许幻山’ or x==‘飒飒’ or x==‘浪浪’:
    return ‘VIP用户’
    elif x==‘NaN’:
    return ‘未知用户’
    else:
    return ‘普通用户’

    df_all[‘danmu_level’] = df_all[‘danmu_role’].apply(transform_name)
    df_all.head()

    Out[6]:

    episodes
    comment_id
    oper_name
    vip_degree
    content
    time_point
    up_count
    danmu_role
    danmu_level
    0
    10
    6691339556383867223
    NaN
    5
    1
    27
    0
    NaN
    普通用户
    1
    10
    6691340141707381348
    沉尘
    2
    王漫妮 : 来了来了
    28
    1
    王漫妮
    VIP用户
    2
    10
    6691340663373931124
    NaN
    5
    钟晓芹 : 第一来了
    29
    1
    钟晓芹
    VIP用户
    3
    10
    6691340707249533722
    NaN
    2
    哈哈哈哈来了
    26
    0
    NaN
    普通用户
    4
    10
    6691340998716925826
    NaN
    0
    每天等更新
    27
    3
    NaN
    普通用户

    数据可视化

    弹幕发送人群等级分布
    In [7]:

    level_num = df_all[‘danmu_level’].value_counts()
    level_num

    Out[7]:
    普通用户 233528
    VIP用户 37521
    Name: danmu_level, dtype: int64
    In [8]:

    data_pair = [list(z) for z in zip(level_num.index.tolist(), level_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([’#6FB27C’, ‘#FFAF34’])
    pie1.render()

    Out[8]:
    ‘C:\Users\wzd\Desktop\CDA\CDA_Python\Python项目实作\影视视频\腾讯视频\三十而已\code\render.html’

    VIP用户最喜欢使用的弹幕角色?
    In [9]:

    role_num = df_all[‘danmu_role’].value_counts()
    role_num

    Out[9]:
    王漫妮 23980
    顾佳 7091
    钟晓芹 3144
    飒飒 1445
    浪浪 732
    陈屿 675
    许幻山 454
    Name: danmu_role, dtype: int64
    In [10]:

    柱形图

    bar1 = Bar(init_opts=opts.InitOpts(width=‘1350px’, height=‘750px’))
    bar1.add_xaxis(role_num.index.tolist())
    bar1.add_yaxis("", role_num.values.tolist(), category_gap=‘5%’)
    bar1.set_global_opts(title_opts=opts.TitleOpts(title=“VIP用户最喜欢使用的弹幕角色”),
    visualmap_opts=opts.VisualMapOpts(max_=21027),
    )
    bar1.render()

    Out[10]:
    ‘C:\Users\wzd\Desktop\CDA\CDA_Python\Python项目实作\影视视频\腾讯视频\三十而已\code\render.html’

    弹幕发送字数分布
    In [24]:

    word_num = df_all.content.apply(lambda x:len(x))
    word_num.describe()

    Out[24]:
    count 271049.000000
    mean 12.112655
    std 6.599164
    min 1.000000
    25% 8.000000
    50% 11.000000
    75% 16.000000
    max 489.000000
    Name: content, dtype: float64
    In [25]:

    word_num = df_all.content.apply(lambda x:len(x))

    分箱

    bins = [0,5,10,15,20,25,30,35,40,45,50,500]
    word_num_cut = pd.cut(word_num, bins, right=False).value_counts()
    word_num_cut = word_num_cut.sort_index()
    word_num_cut

    Out[25]:
    [0, 5) 18720
    [5, 10) 85516
    [10, 15) 83993
    [15, 20) 47592
    [20, 25) 26503
    [25, 30) 7584
    [30, 35) 841
    [35, 40) 163
    [40, 45) 58
    [45, 50) 26
    [50, 500) 53
    Name: content, dtype: int64
    In [26]:

    柱形图

    bar2 = Bar(init_opts=opts.InitOpts(width=‘1350px’, height=‘750px’))
    bar2.add_xaxis(word_num_cut.index.astype(‘str’).tolist())
    bar2.add_yaxis("", word_num_cut.values.tolist(), category_gap=‘4%’)
    bar2.set_global_opts(title_opts=opts.TitleOpts(title=“弹幕发送字数分布”),
    visualmap_opts=opts.VisualMapOpts(max_=72694),
    )
    bar2.render()

    Out[26]:
    ‘C:\Users\wzd\Desktop\CDA\CDA_Python\Python项目实作\影视视频\腾讯视频\三十而已\code\render.html’

    弹幕角色-王漫妮 词云图
    In [27]:

    定义分词函数

    def get_cut_words(content_series):
    # 读入停用词表
    stop_words = []

    with open(r"C:\Users\wzd\Desktop\CDA\CDA_Python\Python文本分析\10.文本摘要\stop_words.txt", 'r', encoding='utf-8') as f:
        lines = f.readlines()
        for line in lines:
            stop_words.append(line.strip())
    


    # 添加关键词
    my_words = [‘王漫妮’, ‘顾佳’, ‘钟晓芹’, ‘陈屿’, ‘许幻山’,
    ‘江疏影’, ‘童瑶’, ‘毛晓彤’, ‘杨玏’, ‘李泽锋’]

    for i in my_words:
        jieba.add_word(i) 
    


    # 自定义停用词
    my_stop_words = [‘真的’, ‘这部’, ‘这是’, ‘一种’, ‘那种’,
    ‘哈哈哈’, ‘哈哈哈哈’, ‘啊啊啊’]
    stop_words.extend(my_stop_words)

    # 分词
    word_num = jieba.lcut(content_series.str.cat(sep=’。’), cut_all=False)

    # 条件筛选
    word_num_selected = [i for i in word_num if i not in stop_words and len(i)>=2]

    return word_num_selected
    

    In [28]:

    df_all[‘danmu_role’] = df_all.danmu_role.str.strip()

    In [29]:

    role_num

    Out[29]:
    王漫妮 24004
    顾佳 7098
    钟晓芹 3147
    陈屿 675
    许幻山 454
    Name: danmu_role, dtype: int64
    In [30]:

    #content_series=df_all[df_all.danmu_role==‘王漫妮’][‘content’]
    content_series1 = df_all[df_all.content.str.replace(pattern, ‘’).str.contains(‘漫妮|疏影’)][‘content’]
    text1 = get_cut_words(content_series1)
    text1[:5]

    Building prefix dict from the default dictionary …
    Loading model from cache C:\Users\wzd\AppData\Local\Temp\jieba.cache
    Loading model cost 1.418 seconds.
    Prefix dict has been built successfully.
    Out[30]:
    [‘江疏影’, ‘妈粉’, ‘军团’, ‘点名’, ‘喜欢’]
    In [31]:

    绘制词云图

    stylecloud.gen_stylecloud(text=’ ‘.join(text1), max_words=1000,
    collocations=False,
    font_path=r’‪C:\Windows\Fonts\msyh.ttc’,
    icon_name=‘fas fa-heart’,
    size=653,
    output_name=’./html/弹幕角色王漫妮-词云图.png’)
    Image(filename=’./html/弹幕角色王漫妮-词云图.png’)

    Out[31]:

    弹幕角色-顾佳 词云图
    In [32]:

    text2 = get_cut_words(content_series=df_all[df_all.danmu_role==‘顾佳’][‘content’])

    text2[:5]

    content_series2 = df_all[df_all.content.str.replace(pattern, ‘’).str.contains(‘顾佳|童瑶’)][‘content’]
    text2 = get_cut_words(content_series2)
    text2[:5]

    Out[32]:
    [‘戒指’, ‘破碎’, ‘顾佳’, ‘离婚’, ‘顾佳’]
    In [33]:

    stylecloud.gen_stylecloud(text=’ ‘.join(text2), max_words=1000,
    collocations=False,
    font_path=r’‪C:\Windows\Fonts\msyh.ttc’,
    icon_name=‘fas fa-star’,
    size=653,
    output_name=’./html/弹幕角色顾佳-词云图.png’)
    Image(filename=’./html/弹幕角色顾佳-词云图.png’)

    Out[33]:

    弹幕角色-钟晓芹 词云图
    In [34]:

    content_series3 = df_all[df_all.content.str.replace(pattern, ‘’).str.contains(‘晓芹|晓彤’)][‘content’]
    text3 = get_cut_words(content_series3)
    text3[:5]

    Out[34]:
    [‘钟晓芹’, ‘胎停’, ‘晓芹’, ‘过分’, ‘晓芹’]
    In [35]:

    stylecloud.gen_stylecloud(text=’ ‘.join(text3), max_words=1000,
    collocations=False,
    font_path=r’‪C:\Windows\Fonts\msyh.ttc’,
    icon_name=‘fas fa-comments’,
    size=653,
    output_name=’./html/弹幕角色钟晓芹-词云图.png’)
    Image(filename=’./html/弹幕角色钟晓芹-词云图.png’)

    Out[35]:

    弹幕角色-陈屿 词云图
    In [36]:

    content_series4 = df_all[df_all.content.str.replace(pattern, ‘’).str.contains(‘陈屿|杨玏’)][‘content’]
    text4 = get_cut_words(content_series4)
    text4[:5]

    Out[36]:
    [‘陈屿’, ‘不行’, ‘陈屿’, ‘鬼鬼祟祟’, ‘陈屿’]
    In [37]:

    stylecloud.gen_stylecloud(text=’ ‘.join(text4), max_words=1000,
    collocations=False,
    font_path=r’‪C:\Windows\Fonts\msyh.ttc’,
    icon_name=‘fas fa-leaf’,
    size=653,
    output_name=’./html/弹幕角色陈屿-词云图.png’)
    Image(filename=’./html/弹幕角色陈屿-词云图.png’)

    Out[37]:

    弹幕角色-许幻山 词云图
    In [38]:

    content_series5 = df_all[df_all.content.str.replace(pattern, ‘’).str.contains(‘幻山’)][‘content’]
    text5 = get_cut_words(content_series5)
    text5[:5]

    Out[38]:
    [‘许幻山’, ‘很会’, ‘老婆’, ‘眼色’, ‘许幻山’]
    In [39]:

    stylecloud.gen_stylecloud(text=’ ‘.join(text5),
    max_words=1000,
    collocations=False,
    font_path=r’‪C:\Windows\Fonts\msyh.ttc’,
    icon_name=‘fas fa-plane’,
    size=653,
    output_name=’./html/弹幕角色许幻山-词云图.png’)
    Image(filename=’./html/弹幕角色许幻山-词云图.png’)

    Out[39]:

    In [40]:

    page1 = Page()
    page1.add(pie1, bar1, bar2)
    page1.render(’./html/三十而已腾讯弹幕数据分析.html’)

    Out[40]:
    ‘C:\Users\wzd\Desktop\CDA\CDA_Python\Python项目实作\影视视频\腾讯视频\三十而已\code\html\三十而已腾讯弹幕数据分析.html’

    更多相关内容
  • 斗鱼弹幕数据分析

    2019-01-09 11:47:15
    https://blog.csdn.net/xbw12138/article/details/81478225 通过分析直播弹幕数据,对主播进一步了解。
  • 腾讯弹幕数据分析实战

    千次阅读 2020-12-22 17:01:15
    腾讯弹幕数据分析实战通用爬虫代码:令人心动的offer2可视化分析批量导入数据并合并数据读取数据处理及清洗重命名过滤字段时间格式转换机械压缩函数处理comment会员等级打标数据分析1.各期弹幕数量对比2.谁是弹幕...

    通用爬虫代码:

    '''
    Date: 2020-12-21 23:27:59
    LastEditTime: 2020-12-22 16:36:43
    '''
    import requests
    import json
    import time
    import pandas as pd
      
    
    def get_danmu_all_page(target_id, vid,filename):
        df = pd.DataFrame()
        for page in range(15, 20000, 30):  #亲测有效
            headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'}
            url = 'https://mfm.video.qq.com/danmu?otype=json&timestamp={0}&target_id={1}vid{2}&count=80'.format(page,target_id,vid)
            print("正在提取第" + str(page) + "页")
            html = requests.get(url,headers = headers)
            bs = json.loads(html.text,strict = False)  #strict参数解决部分内容json格式解析报错
            time.sleep(0.5)
            #遍历获取目标字段
            try:
                for i in bs['comments']:
                    opername = i['opername']
                    content = i['content']  #弹幕
                    upcount = i['upcount']  #点赞数
                    user_degree =i['uservip_degree'] #会员等级
                    timepoint = i['timepoint']  #发布时间
                    comment_id = i['commentid']  #弹幕id
                    cache = pd.DataFrame({'用户id':[opername],'弹幕':[content],'会员等级':[user_degree],'发布时间':[timepoint],'弹幕点赞':[upcount],'弹幕id':[comment_id]})
                    df = pd.concat([df,cache])
            except Exception as e:
                break
        # df.to_csv(f'{filename}.csv',encoding = 'utf-8')
        return df
    #自己按需添加
    target_id = ['6130942571%26','6164313448%26','6194952391%26','6227063464%26']
    vid = ['%3Dt0034o74jpr','%3Dr00346rvwyq','%3Dd0035rctvoh','%3Db0035j0tgo0']
    filename = ['面试篇','第1期','第2期','第3期']
    df = pd.DataFrame()
    for i in range(len(vid)):
        df = get_danmu_all_page(target_id=target_id[i], vid=vid[i],filename=filename[i])#df{}.format(data_dm[i])
        df.insert(0, '所属期数', filename[i])
        df.to_csv(f'{filename[i]}.csv',index=False)
    
    

    令人心动的offer2可视化分析

    import pandas as pd
    import numpy as np
    import pyecharts.options as opts
    from pyecharts.charts import *
    from pyecharts.globals import ThemeType
    

    批量导入数据并合并

    # path = 'D:/Pandas/csv/'
    # #文件目录路径
    # df_all = pd.DataFrame()
    # for i in os.listdir(path):
    #     df_one = pd.read_csv(path+f'{i}', engine='python', encoding='utf-8')  
    #     df_all = df_all.append(df_one, ignore_index=False)#ignore_index:默认值为False,如果为True则不使用index标签
    # df_all.shape
    # #输出
    # df_all.to_excel('offer.xlsx',index=False)
    

    数据读取

    df = pd.read_excel('offer.xlsx')
    df[:10]
    
    所属期数用户id弹幕会员等级发布时间弹幕点赞弹幕id
    0第1期NaN47,第一来了45236732257356663684096
    1第1期NaN第一1856732257393620750336
    2第1期NaN哈哈哈,我还以为我是第一个呢17326732257548063721472
    3第1期NaNYEYEYEY08166732257672952315904
    4第1期NaN来了来了,66186732258003787425792
    5第1期叶湘伦来了0806732258629720189952
    6第1期NaN来了来了0826732258673319944192
    7第1期海浪来啦0806732258806970479616
    8第1期NaN来咯0546732258885488543744
    9第1期熙崽是神仙第一!0796732260786762655744

    数据处理及清洗

    重命名

    所属期数 episodes 用户id user 弹幕 comment 会员等级 grade 发布时间 date 弹幕点赞 likecounts 弹幕id dmid

    df.rename(columns={'所属期数':'episodes','用户id':'user','弹幕':'comment','会员等级':'grade','发布时间':'date','弹幕点赞':'likecounts','弹幕id':'dmid'},inplace=True)
    df.head()
    
    episodesusercommentgradedatelikecountsdmid
    0第1期NaN47,第一来了45236732257356663684096
    1第1期NaN第一1856732257393620750336
    2第1期NaN哈哈哈,我还以为我是第一个呢17326732257548063721472
    3第1期NaNYEYEYEY08166732257672952315904
    4第1期NaN来了来了,66186732258003787425792
    df.info()
    
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 70798 entries, 0 to 70797
    Data columns (total 7 columns):
     #   Column      Non-Null Count  Dtype 
    ---  ------      --------------  ----- 
     0   episodes    70798 non-null  object
     1   user        26409 non-null  object
     2   comment     70797 non-null  object
     3   grade       70798 non-null  int64 
     4   date        70798 non-null  int64 
     5   likecounts  70798 non-null  int64 
     6   dmid        70798 non-null  int64 
    dtypes: int64(4), object(3)
    memory usage: 3.8+ MB
    

    过滤字段

    #对用户进行空值补充
    df['user'] = df['user'].fillna('未知用户')
    #对弹幕进行re匹配处理
    df['comment'] = df['comment'].str.extract(r"([\u4e00-\u9fa5]+)") #提取中文内容
    df = df.dropna()  #纯表情弹幕直接删除
    #提取分析字段
    df = df.iloc[:,:-1]
    df.head()
    
    episodesusercommentgradedatelikecounts
    0第1期未知用户第一来了4523
    1第1期未知用户第一185
    2第1期未知用户哈哈哈1732
    4第1期未知用户来了来了6618
    5第1期叶湘伦来了080

    时间格式转换

    def time_change(seconds):
        m, s = divmod(seconds, 60)
        h, m = divmod(m, 60)
        ss_time = "%d:%02d:%02d" % (h, m, s)
        # print(ss_time)
        return ss_time
    # time_change(seconds=8888)
    #将time_change函数应用于date字段:
    df["date"] = df["date"].apply(time_change)
    #设置为需要的时间格式
    df['date'] = pd.to_datetime(df['date'])
    df['date'] = df['date'].apply(lambda x : x.strftime('%H:%M:%S'))
    

    机械压缩函数处理comment

    #定义机械压缩函数
    def yasuo(st):
        for i in range(1,int(len(st)/2)+1):
            for j in range(len(st)):
                if st[j:j+i] == st[j+i:j+2*i]:
                    k = j + i
                    while st[k:k+i] == st[k+i:k+2*i] and k<len(st):   
                        k = k + i
                    st = st[:j] + st[k:]    
        return st
    # yasuo(st='')
    #调用机械压缩函数
    df["comment"] = df["comment"].astype("str").apply(yasuo)
    

    会员等级打标

    df.grade.value_counts().index.tolist()
    
    [0, 3, 1, 4, 2, 5, 6, 7, 8]
    
    df['grade'] = 'v'+df['grade'].astype('str')#['v'+i for i in df['grade']]
    
    df.sample(2)
    
    episodesusercommentgradedatelikecounts
    9235第1期未知用户王颖飞好像一个演员v000:27:425
    57421面试篇zxz彩虹袜v300:13:0712

    数据分析

    #绘图通用函数
    def get_pyechart(x,y,chart,title,size,pos,theme):
        if chart == 'bar':
            c = (
                Bar(init_opts=opts.InitOpts(theme=theme))
                .add_xaxis(x)
                .add_yaxis("",y) 
                .set_series_opts(label_opts=opts.LabelOpts(font_size=size,position=pos))
                )
        elif chart == 'barh':
            c = (
                Bar(init_opts=opts.InitOpts(theme=theme))
                .add_xaxis(x)
                .add_yaxis("",y).reversal_axis() #X轴与y轴调换顺序
                .set_series_opts(label_opts=opts.LabelOpts(font_size=size,position=pos))
                )
        elif chart == 'pie':
            c = (
                Pie(init_opts=opts.InitOpts(theme=theme))
                .add("", list(zip(x,y)))
                .set_series_opts(label_opts=opts.LabelOpts(formatter="等级{b}占比:{d}%",font_size=size))
                )
        elif chart == 'line':
            c = (
                Line(init_opts=opts.InitOpts(theme=theme))
                .add_xaxis(x)
                .add_yaxis('情感倾向',y, is_smooth=True,is_connect_nones=True,areastyle_opts=opts.AreaStyleOpts(opacity=0.5))
                .set_global_opts(title_opts=opts.TitleOpts(title=title,subtitle="数据来源:腾讯视频",pos_left = 'left'))
                )
        c.set_global_opts(title_opts=opts.TitleOpts(title=title,subtitle="数据来源:腾讯视频",pos_left = 'left'),
                            xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=13)), #更改横坐标字体大小
                            yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=13)), #更改纵坐标字体大小
                            )
        return c.render_notebook()
    

    1.各期弹幕数量对比

    df_e = df['episodes'].value_counts()
    df_e
    
    面试篇    18603
    第3期    18107
    第1期    17551
    第2期    15844
    Name: episodes, dtype: int64
    
    x = df_e.index.tolist()
    y = df_e.values.tolist()
    df_e = get_pyechart(x=x,y=y,chart='bar',title='各期弹幕数量',size=16,pos='top',theme=ThemeType.DARK)
    df_e
    

    在这里插入图片描述

    2.谁是弹幕发射机

    df_u = df['user'].value_counts()[1:10].sort_values(ascending=True)
    df_u
    
    神马不是浮云     78
    .          79
    圣雪天使       80
    。          89
    白龙吟        92
    为时不晚i      93
    momo       93
    ベ☆小强呐     103
    想太多de猫    135
    Name: user, dtype: int64
    
    x = df_u.index.tolist()
    y = df_u.values.tolist()
    df_u = get_pyechart(x=x,y=y,chart='barh',title='弹幕发送数量TOP10',size=16,pos='right',theme=ThemeType.DARK)
    df_u
    

    在这里插入图片描述

    df[df["user"]=="想太多de猫"].sample(10)
    
    episodesusercommentgradedatelikecounts
    17104第1期想太多de猫爱吃辣的都是美女v400:51:549
    20881第2期想太多de猫如果这都是咸鱼v400:09:4510
    1489第1期想太多de猫领带神马的太高端v400:04:4212
    5408第1期想太多de猫谦虚不等于诚实哦v400:15:4912
    57919面试篇想太多de猫大多数父母的想法v400:14:547
    60506面试篇想太多de猫越看越自卑v400:21:3613
    45714第3期想太多de猫这是绝对的高质量对抗v000:37:002
    21397第2期想太多de猫瞿泽林这句对人性的关怀v400:11:0549
    59906面试篇想太多de猫假发了解一下v400:19:5313
    39564第3期想太多de猫个人觉得直接问更好v000:21:491

    3.会员等级分布

    df_g = df['grade'].value_counts().sort_values(ascending=True)
    df_g
    
    v8       12
    v7      135
    v6     1496
    v5     2097
    v2     2499
    v4     2957
    v1     3220
    v3     3403
    v0    54286
    Name: grade, dtype: int64
    
    x = df_g.index.tolist()
    y = df_g.values.tolist()
    df_g = get_pyechart(x=x,y=y,chart='pie',title='会员等级分布',size=14,pos='right',theme=ThemeType.DARK)
    df_g
    

    在这里插入图片描述

    词云图讨论

    import stylecloud
    import jieba
    import os 
    from IPython.display import Image # 用于在jupyter lab中显示本地图
    
    # 定义分词函数
    def get_cut_words(content_series):
        # 读入停用词表
        stop_words = [] 
        with open(r"D:/Pandas/已学习/如何制作stylecloud词云?/stop_words.txt", 'r', encoding='utf-8') as f:
            lines = f.readlines()
            for line in lines:
                stop_words.append(line.strip())
        # 添加关键词
        my_words = ['撒老师', '范丞丞','第一季']  
        for i in my_words:
            jieba.add_word(i) 
        # 自定义停用词
        my_stop_words = ['好像', '真的','感觉']   
        stop_words.extend(my_stop_words)               
        # 分词
        word_num = jieba.lcut(content_series.str.cat(sep='。'), cut_all=False)
        # 条件筛选
        word_num_selected = [i for i in word_num if i not in stop_words and len(i)>=2]
        return word_num_selected
    # 绘制词云图
    text1 = get_cut_words(content_series=df['comment'])
    stylecloud.gen_stylecloud(text=' '.join(text1), max_words=100,
                              collocations=False,
                              font_path='字酷堂清楷体.ttf',
                              icon_name='fas fa-dog',
                              size=512,
                              #palette='matplotlib.Inferno_9',
                              output_name='offer.png')
    Image(filename='offer.png')
    
    Building prefix dict from the default dictionary ...
    Loading model from cache C:\Users\ADMINI~1\AppData\Local\Temp\jieba.cache
    Loading model cost 2.044 seconds.
    Prefix dict has been built successfully.
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PL3JJJhN-1608626592533)(demo-offer_files/demo-offer_39_1.png)]

    4.人物被提及

    丁辉,詹秋怡,王骁,朱一暄,瞿泽林,李晋晔,王颖飞,刘煜成

    #df.str.contains('')虽然不能用来判断,但是可以进行聚合操作
    df_talk = ['丁辉','詹秋怡','王骁','朱一暄','瞿泽林','李晋晔','王颖飞','刘煜成']
    dft = [df['comment'].str.contains(i).sum() for i in df_talk]
    df_t = pd.DataFrame(data={'people':df_talk,'count':dft})
    df_t = df_t.sort_values('count',ascending=False)
    x = df_t['people'].tolist()
    y = df_t['count'].tolist()
    df_t = get_pyechart(x=x,y=y,chart='bar',title='被提及次数',size=16,pos='top',theme=ThemeType.DARK)
    df_t
    

    在这里插入图片描述

    情感分析

    import paddlehub as hub
    #这里使用了百度开源的成熟NLP模型来预测情感倾向
    senta = hub.Module(name="senta_bilstm")
    texts = df['comment'].tolist()
    input_data = {'text':texts}
    res = senta.sentiment_classify(data=input_data)
    df['pos'] = [x['positive_probs'] for x in res]
    #重采样至15分钟
    df.index = pd.to_datetime(df['date'])
    data = df.resample('15min').mean().reset_index()
    
    # #给数据表添加调色板
    # import seaborn as sns
    # color_map = sns.light_palette('orange', as_cmap=True)  #light_palette调色板
    # data.style.background_gradient(color_map)
    
    [2020-12-22 16:27:46,410] [    INFO] - Installing senta_bilstm module
    [2020-12-22 16:27:46,436] [    INFO] - Module senta_bilstm already installed in C:\Users\Administrator\.paddlehub\modules\senta_bilstm
    [2020-12-22 16:27:57,111] [    INFO] - Installing lac module
    [2020-12-22 16:27:57,579] [    INFO] - Module lac already installed in C:\Users\Administrator\.paddlehub\modules\lac
    
    df[:10]
    
    x = data["date"].to_list()
    y = list(data["pos"].round(2))
    df_p = get_pyechart(x=x,y=y,chart='line',title='情感倾向',size=16,pos='top',theme=ThemeType.DARK)
    df_p
    

    在这里插入图片描述

    数据集:

    链接:https://pan.baidu.com/s/1p4O8-SF-IVqnJkH-5Fp3jw
    提取码:love
    复制这段内容后打开百度网盘手机App,操作更方便哦

    总结

    情感分析会比较耗时间

    展开全文
  • 腾讯弹幕数据分析实战-附件资源
  • 慕课《用Python玩转数据》之B站弹幕数据分析 1.源代码 # -*- coding: utf-8 -*- """ Created on Wed May 13 17:01:29 2020 @author: 苏子都 """ import requests import re import numpy as np import pandas as ...

    慕课《用Python玩转数据》之B站弹幕数据分析

    1.源代码

    # -*- coding: utf-8 -*-
    """
    Created on Wed May 13 17:01:29 2020
    
    @author: 苏子都
    """
    
    import requests
    import re
    import numpy as np
    import pandas as pd
    from bs4 import BeautifulSoup
    import datetime
    
    import matplotlib.pyplot as plt
    # from matplotlib.pyplot import MultipleLocator
    
    from pyecharts import Pie
    import webbrowser
    
    from wordcloud import WordCloud
    import jieba
    
    plt.style.use('seaborn-dark')          #设置绘图风格
    
    
    
    barrage_list=[]          #获取到弹幕的内容
    
    def get_barrage():
        """
            爬取弹幕
            返回:
                - barrage_all:     弹幕的详细信息,比如发送者、发送时间等
        """
        url='https://api.bilibili.com/x/v1/dm/list.so?oid=7633504'
        res=requests.get(url)
        res.encoding='utf-8'
        res_xml=res.content.decode('utf-8')
        barrage_all=[]          #除了弹幕内容的其他信息,包括弹幕发送者ID、发送弹幕的时间
        
        #匹配出需要的内容,形式如<d p="4688.02300,1,25,16777215,1566557108,0,6a622490,20664776809512964">战歌起!</d>
        pattern=re.compile('<d.*?>(.*?)</d>')          #匹配出xml文件里面的d标签,获取弹幕内容
        global barrage_list
        barrage_list=pattern.findall(res_xml)
        
        html=res.text
        soup=BeautifulSoup(html,'html.parser')
        for target in soup.find_all('d'):             #弹幕的详细信息包含在d标签里面的p标签,先筛选出所有d标签
            value=target.get('p').split(',')          #获取p标签里面的内容
            
            #根据爬取到的弹幕的详细信息的格式,生成并保存得到的结果
            barrage_all.append({'时间':value[0],'弹幕模式':value[1],'弹幕字号':value[2],'弹幕颜色':value[3],'时间戳':value[4],'弹幕池':value[5],'发送者ID':value[6],'历史弹幕':value[7]})
    
        return barrage_all
    
    
    
    def data_processing(barrage_df):
        """
            数据处理
            参数:
                - barrage_df:     弹幕的所有信息,由弹幕详细信息和弹幕内容组成
        """
        barrage_time=(barrage_df['时间'].astype(float)).astype(int)
        time_list=[]          #存储弹幕发在整个视频的哪一个时间
        
        #将爬取到的“时间”,由秒数变为时分秒的形式
        for a_time in barrage_time:
            m,s=divmod(a_time,60)
            h,m=divmod(m,60)
            a_time=str(h)+':'+str(m)+':'+str(s)
            time_list.append(a_time)
        
        barrage_df['时间']=time_list
        
        #将爬取到的“弹幕模式”,按照数值分割成离散的区间
        barrage_type=barrage_df['弹幕模式'].astype(int)
        areas=[0,3,4,5,6,7,8]
        pattern=['滚动弹幕','底端弹幕','顶端弹幕','逆向弹幕','精准定位','高级弹幕']
        barrage_df['弹幕模式']=pd.cut(barrage_type,areas,right=True,labels=pattern)
        
        barrage_tool=barrage_df['弹幕池'].astype(int)
        areas=[-1,0,1,2]
        pattern=['普通池','字幕池','特殊池']
        barrage_df['弹幕池']=pd.cut(barrage_tool,areas,right=True,labels=pattern)
        
        barrage_timestamp=barrage_df['时间戳'].astype(int)
        timestamp_list=[]          #存储弹幕发送的时间
        
        #把爬取到的时间戳转换成字符串日期时间
        for timestamp in barrage_timestamp:
            timestamp_list.append(datetime.datetime.fromtimestamp(timestamp))
            
        barrage_df['时间戳']=timestamp_list
        
        barrage_df.to_csv('狐妖小红娘王权总篇集弹幕.csv',encoding='utf_8_sig')
    
    
    
    def barrage_analyse_plt():
        """
            根据爬取到本地的信息画图
        """
        #解决画图时出现的中文乱码问题
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.rcParams['axes.unicode_minus'] = False
        
        #因为爬取到的弹幕会包含整点发送的弹幕,此时以时间为轴画图会报错,所以需要以特定格式读取日期或时间,即代码中的parse_dates=['时间戳']
        fox_demon=pd.read_csv('狐妖小红娘王权总篇集弹幕.csv',parse_dates=['时间戳'])
        
        barrage_time=fox_demon['时间']
        time_list=[]          #弹幕在视频中的发送时间
        
        #把弹幕在视频中的发送时间由时分秒的格式变为分钟数
        for a_time in barrage_time:
            h,m,s=a_time.strip().split(':')
            temp=int(h)*60+int(m)+int(s)/60
            time_list.append(temp)
        
        time_df=pd.DataFrame(time_list)
        
        '''
        对时间进行分析并画密度图
        '''
        time_df.plot(kind='kde',label='弹幕密度')        #采用DataFrame的plot方法实现可视化,画出密度图  
        plt.title('王权总篇弹幕密度')
        plt.xlabel('时间/分')
        plt.ylabel('百分比')
        plt.legend(['弹幕密度'])
        plt.xlim(0,)          #限制x轴长度
        # plt.xticks(np.arange(time_df.min(),time_df.max(),10))
        plt.show()
        
        '''
        对弹幕颜色进行分析,并把较多的弹幕颜色作为绘图颜色画柱状图
        '''
        barrage_color=fox_demon['弹幕颜色'].value_counts()          #统计用户发送的弹幕使用同一种颜色的数量
        barrage_color=barrage_color.head(7)                         #选出前七种颜色
        
        favorite_color=[]          #弹幕颜色的十六进制颜色码
        
        #将爬取到的十进制颜色码转换为十六进制颜色码
        for a_color in barrage_color.index:
            temp=hex(a_color)
            temp='#'+temp[2:].upper()
            
            while len(temp)<7:
                temp=temp[0]+'0'+temp[1:]
            
            favorite_color.append(temp)
        
        fig,ax=plt.subplots()
        #画柱状图,颜色为使用较多的弹幕颜色
        plt.bar([1,2,3,4,5,6,7],barrage_color.values,color=favorite_color)
        plt.title('王权总篇弹幕颜色使用数量前七名')
        plt.xlabel('排名')
        plt.ylabel('使用该颜色的弹幕数量')
        plt.show()
        
        # fig.savefig('temp.png',transparent=True)
        
        '''
        对时间戳进行分析,画出直方图,统计出各个时间段发送弹幕的数量
        '''
        barrage_date=fox_demon['时间戳'].dt.hour          #抽取日期信息
        bins=np.arange(0,25,1)-0.5
        fig, ax=plt.subplots()
        barrage_date.hist(bins=bins,grid=False,align='mid')          #画出直方图,统计一天中各个时段的弹幕数量
        plt.title('王权总篇各个时段弹幕数量')
        plt.xlabel('时间段')
        plt.ylabel('弹幕数量')
        
        #设置x轴间隔
        # x_major_locator=MultipleLocator(1)
        # ax.xaxis.set_major_locator(x_major_locator)
        
        plt.xticks(np.arange(0,24,1))
        plt.show()
        
        '''
        对发送者ID进行分析,画出柱状图,统计出本集发送弹幕较多的前十个用户ID
        '''
        barrage_userId=fox_demon['发送者ID'].value_counts()          #统计同一个用户ID发送的弹幕数量
        barrage_userId=barrage_userId.head(10)
        
        fig,ax=plt.subplots()
        plt.bar(barrage_userId.index,barrage_userId.values,color=('r','g','b','c','m','r','g','b','c','m'))
        plt.title('王权总篇发送弹幕前十的用户ID情况')
        plt.xlabel('用户B站ID')
        plt.ylabel('弹幕数量')
        plt.xticks(size='small',rotation=50,fontsize=15)          #对x轴文字进行相应的设置
        plt.show()
        
        '''
        对弹幕内容进行分析,画出饼图,统计出同一弹幕长度的信息
        '''
        barrage_comment=fox_demon['弹幕内容']
        comment_len=[]            #存放每条弹幕的长度
        comment_cloud=''          #所有弹幕合并为一个文本,方便绘制词云时进行分词
        for comment in barrage_comment:
            comment_len.append(str(len(comment))+'个字弹幕')
            comment_cloud=comment_cloud+comment+'\n'
        
        comment_len_sr=pd.Series(comment_len)          #通过数组生成一个series,方便使用value_counts()函数统计相同内容次数
        comment_len_count=comment_len_sr.value_counts()
        
        #通过matplotlib绘制饼图,与之前的DataFrame绘图基本一致
        fig,ax=plt.subplots()
        plt.pie(comment_len_count.values,labels=comment_len_count.index,autopct='%0.2f%%')
        plt.title('王权总篇弹幕长度')
        plt.show()
        # plt.legend(loc='right',ncol=5)          #设置图例
        
        #使用pyecharts库绘制饼图,由于使用matplotlib绘制出来的饼图图片比较小,显示不清晰,功能也不算太好,就使用pyecharts库再画一个饼图
        pie=Pie('狐妖小红娘弹幕内容分析','弹幕长度',title_pos='left',width=1100,height=600)
        pie.add(
            "弹幕长度",
            comment_len_count.index,
            comment_len_count.values,
            is_label_show=True,
            is_more_utils=True,
            legend_pos='right',               #图例居右
            legend_orient='vertical'          #图例以垂直方式显示
        )
        pie.render('fox_demon.html')          #在根目录下生成一个fox_demon.html的文件
        webbrowser.open('fox_demon.html')     #在浏览器中打开保存的文件
        
        '''
        根据弹幕内容,画出词云、“句”云
        '''
        text=' '.join(jieba.cut(comment_cloud))          #分词
        color_mask=plt.imread('susu.jpg')                #读取图片
        
        cloud=WordCloud(
            font_path=' C:\\Windows\\Fonts\\simsun.ttc',          #设置绘制词云的字体
            background_color='white',
            mask=color_mask,                                      #根据读取的图片绘制词云
            max_words=2000,
            max_font_size=1000
        )
        
        #绘制“句”云
        cloud_sentence=WordCloud(
            font_path=' C:\\Windows\\Fonts\\simsun.ttc',
            background_color='white',
            mask=color_mask,
            max_words=500,
            max_font_size=1000
        )
        
        wCloud=cloud.generate(text)          #生成词云
        wCloud_sentence=cloud_sentence.generate(comment_cloud)
        
        wCloud.to_file('cloud.png')
        wCloud_sentence.to_file('cloud_sentence.png')
        
        fig,ax=plt.subplots()
        plt.imshow(wCloud,interpolation='bilinear')          #展示词云
        plt.title('王权总篇弹幕词云')
        plt.axis('off')
        plt.show()
        
        fig,ax=plt.subplots()
        plt.imshow(wCloud_sentence,interpolation='bilinear')
        plt.title('王权总篇弹幕句云')
        plt.axis('off')
        plt.show()
    
    if __name__=='__main__':
        barrage_df=pd.DataFrame(get_barrage())          #生成弹幕详细信息
        barrage_df['弹幕内容']=barrage_list          #合并弹幕内容和弹幕详细信息
        
        #数据处理
        data_processing(barrage_df)
        
        #绘图
        barrage_analyse_plt()
        
    

    2.弹幕数据分析

    2.1. 爬取
    所要爬取的内容如下图:
    在这里插入图片描述

    爬取并处理后得到的数据为:
    在这里插入图片描述

    2.2用户在本集中发送弹幕的时间分析
    在这里插入图片描述

    由上图可知,在视频一开始时便有比较多的弹幕,在视频的第80分钟这一时段便有本集最多的弹幕,这一分钟大约有本集1.4%的弹幕铺天盖地袭来,占据你的屏幕。如下图(PS:截图为每秒弹幕数量,与所统计的每分钟弹幕数量有区别,所以这一秒的弹幕数量会比较少,但这一分钟是全集最多的,统计秒数没有多大意义,毕竟整个视频接近一万秒)
    在这里插入图片描述

    2.3弹幕颜色分析
    在这里插入图片描述

    由上图可知,绝大多数用户使用白色的弹幕,约占所有用户的四分之三,红色、黄色和绿色也有使用。
    在这里插入图片描述

    2.4发送弹幕的时间段分析
    在这里插入图片描述

    由上图可知,用户在一天中的21点至22点发送的弹幕数量最多,在午后至午夜这一时间段发送的弹幕比较多,可能是都起不来床也喜欢熬夜。

    2.5用户ID分析
    在这里插入图片描述

    由上图可知,发送弹幕数量前十的用户基本都发送了30条以上的弹幕,发送弹幕最多的用户甚至发送了70条弹幕,这应该就是真爱粉了吧。

    2.6 弹幕长度分析
    在这里插入图片描述

    在这里插入图片描述

    由上面两张图可知,绝大多数用户发送2-6个字的弹幕,其中4个字弹幕最多,约占所有弹幕的15.5%,也有用户发送了48个字超长的弹幕。

    2.7弹幕词云、“句”云
    在这里插入图片描述

    在这里插入图片描述

    从上图的词云,可以看出本集弹幕的较多词语有“如果”、“我们”、“活着”、“出去”、“万水”、“千山”和“愿意”等等。由于B站的弹幕具有类似于“队列”的形式出现在屏幕之上,所以我就制作了“句”云,旨在画出弹幕里面的高频句子,从上图的“句”云,可以看出本集弹幕的较多弹幕内容有“战歌起”、“如果我们活着出去”、“万水千山”、“你愿意陪我一起看吗”和“就让我成为你的眼睛吧”等等。

    3.写在后面
    这个“爬虫”是通过B站视频的oid去爬取弹幕,所以如果要爬取其他的视频的弹幕,需要获取该视频的oid,爬取实质上是获取存储弹幕的XML文件的内容。博主普通学生一枚,暂时没有能力去同时连续爬取多个网页的弹幕,如有其他的不足,还请多多指教。

    展开全文
  • 旨在分析B站系列视屏

     首先要知道我们要做什么,要是茫无目的那就说明都做不了,我们这次的数据分析

    步骤:

    ① 获取视频url

    ② 获取视频cid

    ③ 获取视频弹幕

    第一步:获取视频url

    解析我在弹幕里直接写了,可以自己看一看,我就不在博客里写了,不好排版

    Get_Url代码部分

    from bs4 import BeautifulSoup
    from selenium import webdriver
    
    url = 'https://space.bilibili.com/517327498/channel/seriesdetail?sid=60119'
    print("------------开始罗翔说评论地址------------")  # 2021-11-6 edg VS DK
    
    # chrome驱动,需要放在Python安装的目录下
    driver = webdriver.Chrome(r"C:\Users\12430\AppData\Local\Programs\Python\Python39\chromedriver.exe")
    
    driver.get(url)
    data = driver.page_source  # 获取到页面信息
    # print(data)
    soup = BeautifulSoup(data, 'lxml')  # 我们可以利用他解析HTML代码,并且在解析HTML代码的时候,如果
    # HTML代码不规范或者不完整,lxml解析器会自动修复或补全代码,从而提高效率
    # print(soup)  # 不信你查看一下
    
    count = 1
    res = []
    
    all = soup.find_all('li', attrs={'class': 'small-item fakeDanmu-item'})  # 找到这个专辑里的视频,只要是
    # B站的专辑都在这个class里
    print("all: ", end="")
    print(all)
    # print(all)  # 不信你看一下
    
    for li in all:
        if count <= 15:  # 罗翔的这个专辑视频就15个,所以爬15次
            a = li.find('a', attrs={'class': 'cover cover-normal'})
            print("这是a: ", end="")
            print(a)
            res.append('https:' + a.get("href"))  # href的格式是//www.bilibili.com/video/BV1k44y1g7Dp这样
            count += 1
        else:
            break
    print(res)
    with open('Urls/链接.txt', 'w') as f:  # 将结果放入这个文件里
        for link in res:
            f.write(link + '\n')
    print("已将全部链接放入到链接.txt文件中")
    

    第二步:获取视频cid

    ① 首先我们要定位到这个cid到第放在了什么鬼地方,发现在下面这个位置

     在script中,我们发现cid好出现在了这个window.__playinfo__中,所以我们要想办法获取他它,这边有一个办法就是startswith()这个方法

    ② 知道cid位置以后就想这么获取它就行了 

    首先用startswith()获取链接,不知道为什么罗翔老师的视频不是//cn开头而是//upos(图一),

    通过正则表达式的方法获取到cid的部分(图二)。

     然后通过一系列的处理获取前9个数字,至此获取cid成功

    Get_Cid 代码部分

    from bs4 import BeautifulSoup
    from selenium import webdriver
    import re
    import time
    
    cids = []
    Urls = []
    
    cid_start = 15
    # sets_end = len(open('Urls/Link.txt', 'r').readlines()) + sets_start - 1
    
    anime_name = "《罗翔读评论》"
    
    with open('Urls/Link.txt', 'r') as f:
        for line in f.readlines():
            Urls.append(line.strip())
    
    print("开始爬取动漫" + anime_name + "所有视频的Cid")
    
    # chrome驱动,需要放在Python安装的目录下
    driver = webdriver.Chrome(r"C:\Users\12430\AppData\Local\Programs\Python\Python39\chromedriver.exe")
    link = ''  # 需要先定义,后面查找url的时候可能会应为找不到url而导致link未定义
    cid = ''
    for url in Urls:
        driver.get(url)
        data = driver.page_source
        soup = BeautifulSoup(data, 'lxml')
    
        all = soup.find_all('script')
        for a in all:
            if str(a).startswith("<script>window.__playinfo__"):  # 必须这样否则找不到
               res = a
        # print(res)
    
        links = re.split(r':', str(res))
        # print("-----------------------")
        # print(links)
    
        for url in links:
            # 这个链接前面是域名,中国的都是以cn开头,但是现在好像不是了
            if url.startswith("//"):  # 不知道为什么有些视频不是//cn开头的,所以用//来实现
                print(url)
                print("-----------------------")
                link = url
                break
        cid = re.findall(".*/(.*)-1-.*", link)
    
        # 获取到视频的cid,存进数组然后一起存进Cid.txt文件中
        cid = cid[0]
    
        # 处理特殊情况下,长度不符合cid,去除尾部部分
        # 需要根据Cid进行特殊处理
        if len(cid) > 9:
            length = len(cid)
            a = length - 9
            cid = cid[:-a]
            # print(cid)
        cids.append(cid)
    
        # 每抓完一个网页休眠5秒
        time.sleep(5)
        print(anime_name + "第" + str(cid_start) + "集Cid爬取完毕")
        cid_start -= 1
        print(cid)
    
    with open('Urls/Cid.txt', 'w') as f:
        for id in cids:
            f.write(id + '\n')
    
    print("已将全部视频的Cid放入到Cid.txt文件中")
    

    第三步:获取视频的弹幕

    ① 首先我们需要一个headers 获取 用户代理 和 Cookie,这个自己用F12找找就行,

    然后开始寻找视频的时间,首先我们发现罗翔老师读评论的第一期和最后一期好像是2020/7/14和

    2022/4/29来着,那么我们就设置2020/7/13到2022/4/30来寻找视频日期

    ②  开始获取弹幕数据,这边就不用图片了,代码太长了

     第一步,首先要知道<d></d>这个标签里的这么多数字是什么

    第一个参数 17.57900 记作DM_time,是弹幕在视频中出现的时间,以秒数为单位。

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

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

    第四个参数 16777215 记作DM_color,是字体的颜色以HTML颜色的十进制为准

    第五个参数 1653783652  记作DM_realTime,是发送弹幕的时间戳

    第六个参数 0 记作DM_pool,是弹幕池 0普通池 1字幕池 2特殊池(高级弹幕)

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

    第八个参数 1062823650710860544 记作DM_id,是弹幕在弹幕数据库中rowID,也就是这条弹幕是历史总弹幕的第几条

    第九个参数 11 这个玩意好像没什么用?

    弹幕本体 记作DM_text

     Get_BulletChat部分

    import re
    import jieba
    from bs4 import BeautifulSoup
    import time
    import pandas as pd
    import requests
    import datetime
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
                      "Chrome/102.0.5005.63 Safari/537.36",
        "Connection": "keep-alive",
        # 这个cookie的获取方法在文档中已说明
        "Cookie": "buvid3=F2278A54-EB90-05CA-6AC4-25606AB151A009225infoc; CURRENT_FNVAL=4048; "
                  "b_lsid=10C7E85F4_1812E57B9D8; _uuid=1CCF3FED-9CA9-4996-69104-410F55A4243FE10121infoc; "
                  "buvid4=AD4080D0-B5E7-8064-1B21-3F1AFE743B2510754-022060418-h0Kdr2RwgtcfH98SEPYQ1Q%3D%3D; "
                  "buvid_fp=16eaee4e45e32b194417c0880035c419; CURRENT_BLACKGAP=0; blackside_state=0; sid=7hhsqlnl; "
                  "rpdid=|(J|)Yllu|k~0J'uYlRJJmmuY; "
                  "b_timer=%7B%22ffp%22%3A%7B%22333.788.fp.risk_F2278A54%22%3A%221812E57C17E%22%2C%22333.999.fp"
                  ".risk_F2278A54%22%3A%221812E5BBF35%22%7D%7D "
    }
    sets = 15  # 最新一期的数字
    anime_name = "罗翔读评论"
    dates = []  # 日期数组,用于填充url
    # 遍历日期  包括begin和end的日期  生成类似2020-04-29的格式的日期
    begin = datetime.date(2020, 7, 13)
    end = datetime.date(2022, 4, 30)
    # 需要一天一天找,所以比较慢
    d = begin
    delta = datetime.timedelta(days=1)  # 一天一天找
    while d <= end:
        dates.append(str(d.strftime("%Y-%m-%d")))
        d += delta
    # print(dates)
    #
    
    Cids = []  # Cid数组,用于填充url
    with open('Urls/Cid.txt', 'r') as f:
        for line in f.readlines():
            Cids.append(line.strip())
    print(Cids)  # 15--1
    
    for cid in Cids:
        print("正在爬取第" + str(sets) + "期的" + anime_name + "弹幕...")
    
        # 每次都要重置这些数据
        dm_data = []  # 弹幕数据
        dm_text = []  # 弹幕本体
        # 弹幕的八个参数和弹幕本体
        DM_time = []  # 弹幕时间
        DM_mode = []  # 弹幕模式
        DM_font = []  # 弹幕类型
        DM_color = []  # 弹幕颜色
        DM_realTime = []  # 弹幕时间戳
        DM_pool = []  # 弹幕池
        DM_userID = []  # 弹幕发送者ID
        DM_id = []  # 弹幕是弹幕数据库中的第几条
    
        DM_text = []
        print("正在爬取第" + str(sets) + "期的弹幕...")
        for date in dates:
            url = 'https://api.bilibili.com/x/v1/dm/list.so?oid=' + cid
            response = requests.get(url=url, headers=headers)  # 返回文本信息
            response.encoding = 'utf-8'
            soup = BeautifulSoup(response.text, 'lxml')  # 建立soup对象
            all = soup.find_all("d")  # d是弹幕标签
            # print(all)
            for d in all:
                # 弹幕数据
                dm_data.append(str(d.get("p")).split(","))  # p是标签
                # 弹幕本体
                dm_text.append(d.get_text())
        print("第" + str(sets) + "集" + " " + str(date) + "数据爬取完毕!")
    
        # 分别把数据存进这几个数组
        for i in dm_data:
            DM_time.append(i[0])
            DM_mode.append(i[1])
            DM_font.append(i[2])
            DM_color.append(i[3])
            DM_realTime.append(i[4])
            DM_pool.append(i[5])
            DM_userID.append(i[6])
            DM_id.append(i[7])
    
        for i in dm_text:
            DM_text.append(i)
    
        #  利用pandas进行csv文件的写入
        dt = {"DM_time": DM_time, "DM_mode": DM_mode, "DM_font": DM_font, "DM_color": DM_color,
              "DM_realTime": DM_realTime, "DM_pool": DM_pool, "DM_userID": DM_userID, "DM_id": DM_id, "DM_text": DM_text}
    
        d = pd.DataFrame(dt)
    
        d.to_csv('./Danmu/Danmu-' + str(sets) + '.csv', encoding='utf-8')  # 存储弹幕信息
        print("已将弹幕放入到Danmu-" + str(sets) + ".csv文件中")
        sets -= 1
    
        # 每抓完一个网页休眠7秒
        print("缓冲中...")
        time.sleep(5)
    
    print("已将罗翔读评论的第①期到第①⑤期的弹幕爬取完毕")
    

    第四步,开始作图

    主要功能:

    import matplotlib.pyplot as plt
    import matplotlib
    import pandas as pd
    import os
    from wordcloud import WordCloud
    import jieba
    
    anime_name = "罗翔读评论"
    file_dir = "./Danmu/"
    # 获取文件名
    files = [files for root, dirs, files in os.walk(file_dir)]
    print(files)
    
    
    # 去重
    def duplicate(files):
        for file in files:
            print(file)
            data_df = pd.DataFrame()
            df = pd.read_csv(file_dir + file, encoding="utf-8-sig", index_col=0, engine='python')
            df = pd.concat([data_df, df])
    
            # 开始去重
            data = df.drop_duplicates(subset=['DM_id'], keep='first')
            data.to_csv(file_dir + file, encoding='utf-8-sig', index=True, index_label="")
        print("去重完毕")
    
    
    # 每一期弹幕总数的变化折线图
    def danmuSumPlot(files):
        print("弹幕总数变化图绘制中...")
        list1 = ['1', '2', '3', '4',
                 '5', '6', '7', '8',
                 '9', '10', '11', '12',
                 '13', '14', '15']
        data_sum = []
        for file in files:
            data = pd.read_csv(file_dir + file, encoding="utf-8-sig", index_col=0)
            data_sum.append(len(data))
    
        matplotlib.rcParams["font.family"] = "SimHei"
        plt.plot(list1, data_sum, "m", ':')
        plt.ylabel("弹幕数量")
        plt.xlabel("《罗翔读评论》期数")
        plt.title("每一期弹幕总数的变化图")
        plt.savefig('./Analysis/弹幕分析图片/弹幕总数变化图', dpi=800)
        plt.show()
        print("绘制完毕")
    
    
    # 发弹幕总数TOP10的用户柱状图
    def danmuUserTopBarh(files):
        print("弹幕TOP20用户图绘制中...")
        datas = []
        for file in files:
            datas.append(pd.read_csv(file_dir + file, encoding="utf-8", index_col=0))
    
        # 先合并全部csv文件,再进行统计
        data = pd.concat(datas)
        data = data.groupby('DM_userID').size().reset_index(name="count")
        data = data.sort_values("count", ascending=False)
    
        label = []  # y轴的值
        width = []  # 给出具体每个直方图的数值
        i = 0
    
        for item in data.values:
            if i < 20:
                label.append(item[0])
                width.append(item[1])
                i += 1
            else:
                break
    
        matplotlib.rcParams["font.family"] = "SimHei"
        y = [20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]  # 给出在y轴上的位置
        plt.barh(y=y, width=width, tick_label=label)  # 绘制水平直方图
        plt.ylabel("用户ID")
        plt.xlabel("弹幕数")
        plt.title("发弹幕总数TOP20的用户柱状图")
        plt.subplots_adjust(left=0.22)  # 控制图片左边的间隔  避免显示不全
        plt.savefig('./Analysis/弹幕分析图片/TOP20柱状图', dpi=600)
        print("绘制完毕")
    
    
    # 每期弹幕密度变化图
    def danmuDensityChange(files):
        print("弹幕密度变化图绘制中...")
        sets = 1
        for file in files:
            data = pd.read_csv(file_dir + file, encoding="utf-8-sig", index_col=0)
            data = data.sort_values("DM_time")
    
            # 先对弹幕发送时间进行取整
            data['DM_time'] = [int(item) for item in data.DM_time]
            data = data.groupby('DM_time').size().reset_index(name="counted")
    
            list2 = [item for item in data.DM_time]
            data_sum = [item for item in data.counted]
            matplotlib.rcParams["font.family"] = "SimHei"
            plt.plot(list2, data_sum, "c")
            plt.ylabel("弹幕数量")
            plt.xlabel("视频时间轴/(秒)")
            plt.title(str(sets) + "期弹幕密度变化图")
            plt.savefig("./Analysis/弹幕密度变化/" + str(sets) + '期弹幕密度变化图', dpi=600)
            sets += 1
        print("绘制完毕")
    
    
    # 每期的弹幕词云,词云已经用jieba库进行去词了
    def danmuWordCloud(files):
        print("弹幕词云绘制中...")
        sets = 1
        for file in files:
            data = pd.read_csv(file_dir + file, encoding="utf-8-sig", index_col=0)
            # 先把全部弹幕信息写成一个字符串,再调用方法
            words = ''
            for item in data.DM_text:
                words += item
    
            words = " ".join(jieba.cut(words))
            # 这个scale参数是画布大小参数,也就是调整分辨率的,10代表是原来的10倍大小,越高分辨率越高
            wd = WordCloud(font_path='simhei.ttf',
                           max_words=80,
                           background_color='white',
                           min_font_size=5,
                           width=1920,
                           height=1080,
                           scale=10).generate(words)
            plt.imshow(wd)
            plt.axis("off")
            wd.to_file("./Analysis/词云/第" + str(sets) + "期词云.jpg")
            sets += 1
        print("绘制完毕")
    
    
    # 每期的弹幕词云(jieba去词以后-带图片背景)
    def danmuWordCloud_Img(files):
        print("弹幕词云绘制中...")
        # df = pd.DataFrame()
        # jieba.load_userdict("./Tools/" + anime_name + "词汇.txt")
        sets = 1
        sets_s = 1
        for file in files:
            data = pd.read_csv(file_dir + file, encoding="utf-8", index_col=0)
            # 先把全部弹幕信息写成一个字符串,再调用方法
            words = ''
    
            for item in data.DM_text:
                words += str(item)
            # print(words)
    
            with open('./自定义文件/stopwords.txt', 'r+', encoding='utf-8') as fp:
                stopwords = fp.read().split('\n')  # 将停用词词典的每一行停用词作为列表中的一个元素
    
            word_list = []  # 用于存储过滤停用词后的分词结果'
            seg_list = jieba.cut(words)
            for seg in seg_list:
                if seg not in stopwords:
                    word_list.append(seg)
    
            words = " ".join(word_list)
    
            mask = plt.imread(
                './Analysis/maskImages/' + anime_name + '.jpg')  # 读取图片作为词云图轮廓
            # if sets == 15:
            #     sets = 1
            # 这个scale参数是画布大小参数,也就是调整分辨率的,10代表是原来的10倍大小,越高分辨率越高
            wd = WordCloud(font_path='simhei.ttf',
                           max_words=800,
                           background_color='white',
                           min_font_size=1,
                           # width=1920,
                           # height=1080,
                           mask=mask,
                           scale=5
                           ).generate(words)
            plt.imshow(wd)
            plt.axis("off")
            wd.to_file("./Analysis/带形状词云/" + anime_name + "第" + str(sets_s) + "集词云_Image.jpg")
            # sets += 1
            sets_s += 1
        print("绘制完毕")
    
    
    # 弹幕颜色直方图
    def DM_color(files):
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.rcParams['axes.unicode_minus'] = False
    
        for file in files:
            data_df = pd.DataFrame()
            data = pd.read_csv(file_dir + file)  # 读取数据文件
            data = pd.concat([data_df, data])  # 拼接数据
    
        data_color = data['DM_color'].value_counts()  # 统计用户发送的弹幕使用同一种颜色的数量
        data_color = data_color.head(7)  # 选出前七种颜色
    
        favorite_color = []  # 弹幕颜色的十六进制颜色码
    
        # 将爬取到的十进制颜色码转换为十六进制颜色码
        for a_color in data_color.index:
            temp = hex(a_color)
            temp = '#' + temp[2:].upper()
    
            while len(temp) < 7:
                temp = temp[0] + '0' + temp[1:]
    
            favorite_color.append(temp)
    
        fig, ax = plt.subplots()
        # 画柱状图,颜色为使用较多的弹幕颜色
        plt.bar([1, 2, 3, 4, 5, 6, 7], data_color.values, color=favorite_color)
        plt.title(anime_name + '弹幕颜色使用数量前七名')
        plt.xlabel('排名')
        plt.ylabel('使用该颜色的弹幕数量')
        # plt.show()
    
        fig.savefig(r'./Analysis/弹幕分析图片/' + anime_name + 'Color.png', transparent=True)  # 保存
    
    
    if __name__ == '__main__':
        # # 去重
        duplicate(files[0])
        # 每一期弹幕总数的变化折线图
        danmuSumPlot(files[0])
        # 发弹幕总数TOP20的用户柱状图
        danmuUserTopBarh(files[0])
        # 弹幕颜色直方图
        DM_color(files[0])
        # 每期弹幕密度变化图
        danmuDensityChange(files[0])
        # 每期的弹幕词云
        danmuWordCloud(files[0])
        # 每期的弹幕词云(jieba去词以后-带图片背景)
        danmuWordCloud_Img(files[0])
    

    这边就贴一张结果图片当实例吧

    最后鸣谢这篇文章对我的帮助:(1条消息) python大作业——B站弹幕数据爬取与分析_lkx_icy的博客-CSDN博客_python爬取b站弹幕并进行数据分析

    展开全文
  • 通过弹幕分析主播行为 就是通过弹幕能够分析一些主播行为的偏向,色情淫秽、侮辱谩骂、血腥暴力、反动政治、其他 作者: 1、这玩意儿是我大三时候写的,这个代码也比较次 2、荡下来代码后,要跑起来步骤如下: (1)...
  • 弹幕爬取+高频词分析+词云展示
  • 成果展示 项目地址爬取弹幕可以看我之前写的这篇文章:10行代码下载B站弹幕下载代码# download.py'''依赖模块pip install requests'''import reimport requestsurl = input('请输入B站视频链接: ')res = requests....
  • 很不幸的是,由于疫情的关系,原本线下的AWD改成线上CTF了。这就很难受了,毕竟AWD还是要比CTF难一些的,与人斗现在变成了与主办方斗。 虽然无奈归无奈,但是现在还是得打起精神去面对下一场比赛。...
  • 本项目,就是对B站弹幕数据进行分析。选取分析的对象是B站上点播量过1.4亿的一部剧《Re:从零开始的异世界生活》。2.算法分两部分:第一部分:2.1在《Re:从零开始的异世界生活》的首页面,找到共25集的所有对应播放...
  • 简介:大正时期,日本。... cid_list = [125463156, 126679498, 87351529, 130657281, 130657521, 132024713, 132024933, 134549763, 134547528, 134548247, 97118642, 134548562] 因此对应的弹幕:...
  • barrageAnalysisCN中文弹幕情感分析CMD Recordpython logProcess.py server.log | grep -v '[empty] line' > barrage.temppython segment.py > seg.tempyeal刘洋,git账号:xxyliuyangeric徐沛阳,github账号:...
  • 本次数据分析使用的数据来源腾讯视频的《奔跑吧》第九季第八期的弹幕数据。 2.数据概述 数据格式为JSON格式数据,包含在回调函数中,需使用正则表达式提取出来后再进行后续数据分析操作 3.依赖包及格式文件介绍 ...
  • 电视剧《都挺好》弹幕数据分析

    千次阅读 2019-04-12 21:27:14
    剧很精彩,但追剧界有句俗话说得好:“弹幕往往比剧更精彩”,为了让精彩延续下去,我终究没能忍住对(腾讯视频)弹幕下手。 共计爬取了 394452 条弹幕(雨露均沾,每集平均 8575 条,每 30s 的间隔爬取),来挖一挖...
  • 1.2背景本文档介绍的产品是基于弹幕评论的大数据分析平台,该软件面向直播平台主播和直播平台用户。主要是利用国内知名的直播平台——斗鱼,通过其弹幕服务器第三方接入
  • 2、系统登录图2.1打开浏览器,进入斗鱼弹幕大数据网站 3、系统布局介绍图3.1如上图3.1所示,右侧属于该系统的核心功能栏目,分为管理员管理,系统管理,系统统
  • ——以《都挺好》弹幕数据为例 数据爬取 1.1数据定位 以腾讯视频《都挺好》为元数据材料,选取2019年3月1日开播以来到2019年4月15日46集的所有弹幕数据为研究对象。打开chrome,F12审查元素,其中以...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,950
精华内容 3,580
关键字:

弹幕数据分析

友情链接: 813des.rar