实战 | Python爬取B站柯南弹幕+Gephi梳理主线剧情

皖渝 凹凸数据

作者:皖渝
来源:凹凸数据

一、爬取介绍

利用Chrome浏览器抓包可知,B站的弹幕文件以XML文档式进行储存,如下所示(共三千条实时弹幕)


其URL为:http://comment.bilibili.com/183362119.xml

数字183362119则代表该视频专属ID,通过改变数字即可得到相应的弹幕文件。打开第1集的视频,查看源码,如下图所示。

不难看出,CID则是对应着各个视频的ID,接下来用正则提取即可。

完整爬取代码如下

import requestsimport refrom bs4 import BeautifulSoup as BSimport ospath='C:/Users/dell/Desktop/柯南'if os.path.exists(path)==False:    os.makedirs(path)os.chdir(path)def gethtml(url,header):    r=requests.get(url,headers=header)    r.encoding='utf-8'    return r.textdef crawl_comments(r_text):    txt1=gethtml(url,header)    pat='"cid":(\d+)'    chapter_total=re.findall(pat,txt1)[1:-2]    count=1    for chapter in chapter_total:        url_base='http://comment.bilibili.com/{}.xml'.format(chapter)        txt2=gethtml(url_base,header)        soup=BS(txt2,'lxml')        all_d=soup.find_all('d')        with open('{}.txt'.format(count),'w',encoding='utf-8') as f:            for d in all_d:                f.write(d.get_text()+'\n')        print('第{}话弹幕写入完毕'.format(count))        count+=1if __name__=='__main__':    url='https://www.bilibili.com/bangumi/play/ep321808'    header={'user-agent':'Opera/12.80 (Windows NT 5.1; U; en) Presto/2.10.289 Version/12.02'}    r_text=gethtml(url,header)    crawl_comments(r_text)

最终的全部弹幕文件都在桌面的"柯南"文件下


注:这里共爬取到980个弹幕文件。【B站的柯南自941集后就跳到994集(大会员才能观看的)。虽然目前更新到1032话,但并没有1032集内容,如下图所示】

二、弹幕可视化

I.主要人物讨论总次数分析

(1)统计人数总次数

注:role.txt是主要人物名文件(需考虑到弹幕一般不会对人物的全名进行称呼,多数使用的是昵称,否则可能与实际情况相差较大。)

import jiebaimport osimport pandas as pdos.chdir('C:/Users/dell/Desktop')jieba.load_userdict('role.txt')role=[ i.replace('\n','') for i in open('role.txt','r',encoding='utf-8').readlines()]txt_all=os.listdir('./柯南/')txt_all.sort(key=lambda x:int(x.split('.')[0]))  #按集数排序count=1def role_count():df = pd.DataFrame() for chapter in txt_all:     names={}     data=[]     with open('./柯南/{}'.format(chapter),'r',encoding='utf-8') as f:         for line in f.readlines():             poss=jieba.cut(line)             for word in poss:                 if word in role:                     if names.get(word) is None:                         names[word]=0                     names[word]+=1         df_new = pd.DataFrame.from_dict(names,orient='index',columns=['{}'.format(count)])            df = pd.concat([df,df_new],axis=1)     print('第{}集人物统计完毕'.format(count))     count+=1df.T.to_csv('role_count.csv',encoding='gb18030')

(2)可视化

import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif']=['kaiti']plt.style.use('ggplot')df=pd.read_csv('role_count.csv',encoding='gbk')df=df.fillna(0).set_index('episode')plt.figure(figsize=(10,5))role_sum=df.sum().to_frame().sort_values(by=0,ascending=False)g=sns.barplot(role_sum.index,role_sum[0],palette='Set3',alpha=0.8)index=np.arange(len(role_sum))for name,count in zip(index,role_sum[0]):    g.text(name,count+50,int(count),ha='center',va='bottom',)plt.title('B站名侦探柯南弹幕——主要人物讨论总次数分布')plt.ylabel('讨论次数')plt.show()


虽说是万年小学生,柯南还是有变回新一的时候,且剧情也并不只是"找犯人—抓犯人"。接下来从数据的角度来,扒扒一些精彩剧情集数。

II.柯南变回新一集数统计

考虑到部分集数中新一是在回忆中出现的,为减少偏差,将讨论的阈值设为250次,绘制如下分布图

其讨论次数结果及剧集名如下表所示

有兴趣的朋友可以码一下,除235集外,均是柯南变回新一的集数。

相关代码如下:

df=pd.read_csv('role_count.csv',encoding='gbk')df=df.fillna(0).set_index('episode')xinyi=df[df['新一']>=250]['新一'].to_frame()print(xinyi) #新一登场集数plt.figure(figsize=(10,5))plt.plot(df.index,df['新一'],label='新一',color='blue',alpha=0.6)plt.annotate('集数:50,讨论次数:309',              xy=(50,309),             xytext=(40,330),             arrowprops=dict(color='red',headwidth=8,headlength=8)            )plt.annotate('集数:206,讨论次数:263',              xy=(206,263),             xytext=(195,280),             arrowprops=dict(color='red',headwidth=8,headlength=8)            )plt.annotate('集数:571,讨论次数:290',              xy=(571,290),             xytext=(585,310),             arrowprops=dict(color='red',headwidth=8,headlength=8)            )plt.hlines(xmin=df.index.min(),xmax=df.index.max(),y=250,linestyles='--',colors='red')plt.legend(loc='best',frameon=False)plt.xlabel('集数')plt.ylabel('讨论次数')plt.title('工藤新一讨论次数分布图')plt.show()

以讨论次数最多的572集,绘制词云图(剔除了高频词"新一",防止遗漏其他信息)如下所示:

从图中可看出,出现频率较高地词有整容、服部、声音、爱情等。(看来凶手是整成了新一的模样进行犯罪的,还有新兰的感情戏在里面,值得一看)

III.主线集数内容分析

主线剧情主要是围绕着组织成员(琴酒、伏特加、贝尔摩德)展开,绘制分布图如下:

plt.figure(figsize=(10,5))names=['琴酒','伏特加','贝姐']colors=['#090707','#004e66','#EC7357']alphas=[0.8,0.7,0.6]for name,color,alpha in zip(names,colors,alphas):    plt.plot(df.index,df[name],label=name,color=color,alpha=alpha)plt.legend(loc='best',frameon=False)plt.annotate('集数:{},讨论次数:{}'.             format(df['贝姐'].idxmax(),int(df['贝姐'].max())),              xy=(df['贝姐'].idxmax(),df['贝姐'].max()),             xytext=(df['贝姐'].idxmax()+30,df['贝姐'].max()),             arrowprops=dict(color='red',headwidth=8,headlength=8)            )plt.xlabel('集数')plt.ylabel('讨论次数')plt.title('酒厂成员讨论次数分布图')plt.hlines(xmin=df.index.min(),xmax=df.index.max(),y=200,linestyles='--',colors='red')plt.ylim(0,400)#输出主线剧集mainline=set(list(df[df['贝姐']>=200].index)+list(df[df['琴酒']>=200].index))  #伏特加可忽略不计print(mainline) 

从上图分析可知,组织成员的行动基本一致,其中贝姐(贝尔摩德)的人气在三人中是较高的,特别是在375集(与黑暗组织直面对决系列),讨论次数高达379。此外,统计其讨论次数大于200次的集数,结果如下:

以讨论次数最高的375集为内容,绘制词云图(剔除了高频词"贝姐",防止遗漏其他信息)如下

从图中可知,天使、琴酒、干妈、心疼、狙击手等词汇出现频率较高。从词频较低的败北主线中可以看出,这次酒厂行动应该是失败告终。

三、人物形象网络分析

I.合并txt文件

为尽可能反映出弹幕观众对人物形象的描述,考虑到一集弹幕共3000条,为减少运行成本,这里仅选取特定人物讨论次数最多的20集合并后再进行分析。

import osimport pandas as pddf=pd.read_csv('role_count.csv',encoding='gbk')df=df.fillna(0).set_index('episode')huiyuan_ep=list(df.sort_values(by='灰原哀',ascending=False).index[:20])mergefiledir = 'C:/Users/dell/Desktop/柯南'file=open('txt_all.txt','w',encoding='UTF-8')   count=0for filename in huiyuan_ep:    filepath=mergefiledir+'/'+str(filename)+'.txt'    for line in open(filepath,encoding='UTF-8'):        file.writelines(line)    file.write('\n')    count+=1    print('第{}集写入完毕'.format(count))file.close()

II.人物形象可视化

借助共现矩阵的思想,即同一句话中出现两个指定的词则计数1。指定起始点Source为灰原哀,代码如下所示:(注:其中,stopwods.txt为停止词文件,role.txt为人物昵称文件)

import codecsimport csvimport jiebalinesName=[]names={}relationship={}jieba.load_userdict('role.txt')txt=[ line.strip() for line in open('stopwords.txt','r',encoding='utf-8')]name_list=[ i.replace('\n','') for i in open('role.txt','r',encoding='utf-8').readlines()]def base(path):    with codecs.open(path,'r','UTF-8') as f:        for line in f.readlines():            line=line.replace('\r\n','')            poss = jieba.cut(line)            linesName.append([])            for word in poss:                  if word in txt:                    continue                linesName[-1].append(word)                if names.get(word) is None:                    names[word]=0                    relationship[word]={}                names[word]+=1    return linesName,relationshipdef relationships(linesName,relationship,name_list):              for line in linesName:        for name1 in line:            if name1 in name_list:                for name2 in line:                    if name1==name2:                        continue                    if relationship[name1].get(name2) is None:                        relationship[name1][name2]=1                    else:                        relationship[name1][name2]+=1    return relationshipdef write_csv(relationship):    csv_writer2=open('edges.csv','w',encoding='gb18030')    writer=csv.writer(csv_writer2,delimiter=',',lineterminator='\n')    writer.writerow(['Source','Target','Weight'])    for name,edges in relationship.items():        for k,v in edges.items():            if v>10:                writer.writerow([name,k,v])    csv_writer2.close()    if __name__=='__main__':    linesName,relationship=base('txt_all.txt')    data=relationships(linesName,relationship,name_list)    write_csv(data) 

将生成的文件导入Gephi,得到如下人物形象图

线条越粗的线,代表该人物特征越明显。不难看出,大家对于哀酱的评价主要是美腻、可爱、心疼。

再做一张琴酒的~

哈哈哈,大家对琴酒的评价就比较逗逼了,变态,痴汉,聪明啥都有~

你以为的琴酒,实际上的琴酒(手动滑稽


以上就是本次python实战的全部内容~

欢迎大家关注皖渝的博客:

https://blog.csdn.net/shine4869/article/details/107381791

©著作权归作者所有:来自51CTO博客作者mb5fe18e5a55d8d的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 基于PHP实现短信验证码发送次数限制解析
  2. php统计2个数据中同时出现的次数最多的单词
  3. PHP结合Redis来限制用户或者IP某个时间段内访问的次数
  4. 确定记录出现的次数
  5. 计算mysql中每天的发生次数
  6. python1.返回一个字符串中出现次数第二多的单词 2.字符串中可能
  7. 腾讯应用宝采集数据分析
  8. java 正则表达式查找某段字符串中所有小写字母开头的单词并统计

随机推荐

  1. 芋道 Spring Boot JPA 入门(一)之快速入门
  2. 干货丨如何使用Redash连接DolphinDB数据
  3. 惊呆了!不改一行 Java 代码竟然就能轻松解
  4. 设置id从1开始自增
  5. zdz工具箱v1.5 android版本发布了,集成各
  6. 什么是Azure Backup
  7. 牛逼 IDE 插件,一键部署 Docker 镜像,开发
  8. 芋道 Spring Cloud Alibaba 介绍
  9. 芋道 Spring Boot 快速入门
  10. 阿里云也有 IDEA 插件 Cloud Toolkit