python⼤作业——B站弹幕数据爬取与分析
B站弹幕数据分析
第⼀部分——使⽤爬⾍抓取弹幕数据
1. B站弹幕数据分析,⾸先我们需要抓取到B站视频的弹幕数据,才能进⾏数据分析
2. 选取分析的对象是B站UP主 观视频⼯作室 的**《睡前消息》** 系列视频中的最新15期,即 110-124期视频(2020-05-03
~ 2020-06-05) 的弹幕作为本次分析的弹幕,爬取的⽇期从第110期发布的⽇期开始到爬取的时候**(2020-05-03 ~
2020-06-09)**
3. ⾸先需要从 观视频⼯作室 的个⼈主页处到 睡前消息 频道,爬这⾥就可以获取到所需要的视频链接,页⾯是动态页⾯,所
以这⾥选择⽤ selenium库 爬取链接,存进⽂件备⽤
注意这⾥我⽤的是⽐较偷懒的爬取⽅法,只能爬到最新15期,要爬其他的可以⾃⼰改进⼀下算法
python新手代码userid4. 在视频页的console处可以输⼊window.cid来获取cid,但在selenium模拟中往浏览器console处输⼊的⽅法,搜索苦久⽆
果,所以想出了如此下策:在视频页打开F12,在elements处搜索cid,发现是有的,这条语句是与⽹关有关的,通过bs4匹
配到该语句,⽤正则匹配出来即可
正则前缀/ 后缀-1-
5. 要爬取B站的弹幕,有两种⽅法 ( 据我所知 )
上述⽅法都需要⽤到cookie,可以⽤以下的⽅法来获取cookie
6. 接下来就是分析这个xml⽂件中的弹幕数据,例⼦为如下:
<d p="369.34300,1,25,16777215,1590515762,0,a6fb6c47,33226011652915207">脱发</d>
这个 p字段 中的参数含义为如下:(百度搜索得到的答案)
第⼀个参数 369.34300 记作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颜⾊的⼗进制为准
第五个参数 1590515762 记作DM_realTime,是发送弹幕的时间戳
第六个参数 0 记作DM_pool,是弹幕池 0普通池 1字幕池 2特殊池(⾼级弹幕)
第七个参数 a6fb6c47 记作DM_userID,是发送者的ID,⽤于“屏蔽此弹幕的发送者”功能
第⼋个参数 33226011652915207 记作DM_id,是弹幕在弹幕数据库中rowID,也就是这条弹幕是历史总弹幕的第⼏条
p字段以外的 弹幕本体 记作DM_text
7. 把爬取到的弹幕分别放到多个csv⽂件中,每⼀期⼀个csv⽂件,⽅便后⾯的数据分析
8. ⾄此爬取数据部分完成
第⼆部分——使⽤Pandas库进⾏数据分析
1. 在爬取并保存了所有弹幕数据之后,先进⾏去重,可对⽐还未去重时⽂件的⼤⼩和去重后⽂件的⼤⼩
1. 在爬取并保存了所有弹幕数据之后,先进⾏去重,可对⽐还未去重时⽂件的⼤⼩和去重后⽂件的⼤⼩
1.1 未去重:(⾄于110-112和113-124⽇期不⼀样,是因为抓113-124的时候被封了IP,只能等到第⼆天早上抓110-
112)
1.2 去重后:
2. 然后进⾏如下的可视化分析:
2.1 每⼀期弹幕总数的变化 折线图
结合上图,我们发现每期的弹幕总数统计波动有些⼤,其中⼀些弹幕数,⽐如116期,甚⾄在这⾥统计只有不到5000条,但是在B站上可以看到:
这⼀期其实总弹幕是有1.4W的,统计到的弹幕数仅占1/3左右,出现这种情况是由于 在视频发出的某⼀天⾥,⼤多数⽤户发过了弹幕,⽽这部分弹幕超出了B站统计的maxlimit ,导致我们没办法统计到这部分弹幕。
相对⽽⾔,弹幕数多的视频就是弹幕不仅仅在某⼀天⼤量被发出,⽐如115期,这⾥我们统计到了有**9000+**的弹幕数,⽽B站上的数据:
统计到的弹幕⼤约占70%,这是由于并没有很多⽤户在某⼀个⽇期⼤量发出弹幕,导致弹幕库溢出,也从某⽅⾯说明了该视频的受众时间较⼴,是⼀个较为优质的视频。
另外,加上我去把每期的标题和弹幕数⼀对应,发现,涉及到 国与国之间的时评 的时候,在播放量相差不多的情况下,视频的受众时间会⽐较⼴,相对的,谈论的时事范围或格局越⼩,受众时间会相对应减⼩。当然这些都是通过⼀⼩部分数据得出的结论,不能代表完全的趋势就是这样。
2.2 统计发弹幕总数TOP10 的⽤户 横向柱状图
⼀共15期的节⽬,根据不完全统计,这位ID为 13631380 的⽤户⼀共发了160+条弹幕,平均每⼀期要发11条弹幕,是真爱粉⽆误了。
2.3 统计每期弹幕密度变化图 (图太多,只放了总体的缩略图)
⾸先从个体上观察这些弹幕密度图,发现弹幕都是较为均匀的,但从总体上观察这些弹幕密度图的时候,发现其中112-118期的弹幕密度图极其相似,119-124期的弹幕密度图也是极其相似,总的来说,1
12-124期都会有⼀个密度⼤且会持续⼀⼩段时间的“弹幕风云”,更巧的是,这部分都集中在视频时间700秒左右,也就是11分-13分之间会有⼀波弹幕的⼩⾼潮。
为此我特意去再次观看**《睡前消息》,发现在112-118期中,节⽬⼤概都在15~20分钟左右,⽽在11-13分钟的时候,也就是在视频时间过去⼤概70%**左右的时候,主持⼈都会作出⼀些毒辣的点评,从⽽引起弹幕的激烈讨论。
2.4 绘制出每期视频的弹幕词云 (取其中⼏个词云图展⽰)
由于我设置了最⼩字体为10,所以如果是弹幕种类分布得⽐较⼴泛的视频,留⽩处会⽐较多,这⾥我选取了较为饱满的弹幕词云图作为展⽰
【睡前消息111】深圳房价这样涨下去,会变成第⼆个⾹港么?
【睡前消息112】阅⽂风波的背后,腾讯真的⼤到只⼿遮天了吗?
【睡前消息118】《后浪》过后,如何看待B站⼜要《⼊海》?
可见弹幕⾥⾯的 同意 ⽀持 保护 之类的字眼⽐较多,**仅观表象的话 **可以说明,虽然该节⽬主持⼈虽嘴巴毒辣,在视频弹幕⾥会造成不少的⼈激烈讨论,但还是有⼤部分⼈同意这些观点的。
项⽬代码
项⽬⽬录结构
GetUrl.py
from bs4 import BeautifulSoup
from selenium import webdriver
url ='space.bilibili/54992199/channel/detail?cid=82529' print("开始爬取《睡前消息》第110-124期视频地址")
# chrome驱动,需要放在Python安装的⽬录下
driver = webdriver.Chrome(r"E:\")
<(url)
data = driver.page_source
soup = BeautifulSoup(data,'lxml')
count=1
res =[]
all= soup.find_all('li', attrs={'class':'small-item fakeDanmu-item'}) for li in all:
if count<=15:
a=li.find('a',attrs={'class':'cover cover-normal'})
res.append('https:'+a.get("href"))
count+=1
else:
break
with open('','w')as f:
for link in res:
f.write(link+'\n')
print("已将全部链接放⼊到⽂件中")
GetCid.py
from bs4 import BeautifulSoup
from selenium import webdriver
import re
import time
cids=[]
Urls=[]
with open('','r')as f:
for line adlines():
Urls.append(line.strip())
print("开始爬取《睡前消息》第110-124期视频的Cid")
# chrome驱动,需要放在Python安装的⽬录下
driver = webdriver.Chrome(r"E:\")
for url in Urls:
<(url)
data = driver.page_source
soup = BeautifulSoup(data,'lxml')
all= soup.find_all('script')
for a in all:
if str(a).startswith("<script>window."):
res=a
links=re.split(r'\:',str(res))
for url in links:
# 这个链接前⾯是域名,中国的都是以cn开头
if url.startswith("//cn"):
link=url
break
cid=re.findall(".*/(.*)-1-.*", link)
# 获取到视频的cid,存进数组然后⼀起存进⽂件中
cid=cid[0]
# 处理特殊情况下,长度不符合cid,去除尾部部分
if len(cid)>9:
length=len(cid)
a=length-9
cid=cid[:-a]
cids.append(cid)
# 每抓完⼀个⽹页休眠5秒
time.sleep(5)
with open('','w')as f:
for id in cids:
f.write(id+'\n')
print("已将全部视频的Cid放⼊到⽂件中")
GetBulletChat.py
from bs4 import BeautifulSoup
import time
import pandas as pd
import requests
import datetime
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 QIHU 360EE",
"Connection":"keep-alive",
# 这个cookie的获取⽅法在⽂档中已说明
"Cookie":""
}
sets=124# 最新⼀期的数字
dates=[]# ⽇期数组,⽤于填充url
# 遍历⽇期包括begin和end的⽇期⽣成类似2020-05-03的格式的⽇期
begin = datetime.date(2020,5,3)
end = datetime.date(2020,6,9)
d = begin
delta = datetime.timedelta(days=1)
delta = datetime.timedelta(days=1)
while d <= end:
dates.append(str(d.strftime("%Y-%m-%d")))
d += delta
Cids=[]# Cid数组,⽤于填充url
with open('','r')as f:
for line adlines():
Cids.append(line.strip())
for cid in Cids:
# 每次都要重置这些数据
dm_data =[]# 弹幕数据
dm_text =[]# 弹幕本体
# 弹幕的⼋个参数和弹幕本体
DM_time =[]
DM_mode =[]
DM_font =[]
DM_color =[]
DM_realTime =[]
DM_pool =[]
DM_userID =[]
DM_id =[]
DM_text =[]
print("正在爬取第"+str(sets)+"期的《睡前消息》弹幕...")
for date in dates:
# 该⽅法已经失效
# url="api.bilibili/x/v2/dm/history?type=1&oid="+cid+"&date="+date
# 暂且采⽤弹幕获取量较少的⽅法
url="comment.bilibili/"+cid+".xml"
(url=url,headers=headers)#返回⽂本信息
soup=,'lxml')#建⽴soup对象
all=soup.find_all("d")
for d in all:
# 弹幕数据
dm_data.append(("p")).split(","))
# 弹幕本体
dm_text._text())
# 分别把数据存进这⼏个数组
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)
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)
<_csv('./Danmu/Danmu-'+str(sets)+'.csv',encoding='utf-8-sig')#存储弹幕信息
print("已将弹幕放⼊到Danmu-"+str(sets)+".csv⽂件中")
sets-=1
# 每抓完⼀个⽹页休眠7秒