- 昨天看人讨论小米拆机的事儿,就想看看数据。
- 其实我们有弹幕评论等等的获取和分析工具,但不方便分享。
- 刚好旧的工具不支持历史弹幕( B 站前一阵更新后需要 cookies 了)。
- 刚才简单写了一个,避开了所有私有的工具,都引用的基本模块,有兴趣的可以玩玩。
结构
用法
- 三个文件放到一个文件夹内,运行
get_all_history_danmaku.py,会生成一个 json。
- 然后就可以随意分析了,熟悉 pandas 的话会方便一些。
- 我们比较常用的是检测时间密度,发送密度,内容同质化,作者分布,等等。
- 至于结果怎么理解,这个见仁见智了。不发表意见,不站队。
文件
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Load bilibili history danmaku, and return json.
import requests
import logging as log
import json
import time
from lxml import etree
from .headers import headers
def get_history_danmaku(oid, date):
dm_list = []
# get data
url = f'https://api.bilibili.com/x/v2/dm/history'
params = {'type': 1, 'oid': oid, 'date': date}
r = requests.get(url, params=params, headers=headers)
content = r.content
log.debug(content.decode('utf-8'))
# read xml
xml = etree.HTML(content)
for d in xml.xpath('//d'):
attrs = d.xpath('./@p')[0]
attrs = attrs.split(',')
text = d.xpath('./text()')[0]
log.debug(f'{attrs}, {text}')
# format data
d = {
'cid': int(oid),
'time': int(float(attrs[0])), # 发送时间点(视频播放点)
'position': int(attrs[1]), # 弹幕位置
'fontsize': int(attrs[2]), # 字体大小
'color': ('000000' + str(hex(int(attrs[3])))[2:])[-6:], # 弹幕颜色
'ctime': int(attrs[4]), # 弹幕创建时间
'unknown': attrs[5],
'author': attrs[6], # 发送者编号(不同于 uid )
'dmid': int(attrs[7]), # 弹幕 id
'content': text, # 弹幕内容
'date': date,
'updateTime': int(time.time())
}
dm_list.append(d)
return dm_list
if __name__ == '__main__':
log.basicConfig(level=log.DEBUG)
oid = 136870419
date = '2019-12-20'
d = get_history_danmaku(oid, date)
print(json.dumps(d, ensure_ascii=False, indent=4))
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests
import logging as log
import os
import re
import json
from datetime import datetime, timedelta
from .get_danmaku import get_history_danmaku
from .headers import headers
def get_all_history_danmaku(aid):
url = f'https://www.bilibili.com/video/av{aid}'
body = requests.get(url).text
log.debug(body)
# get cid / oid
pages = re.findall(r'(?<="pages":)\[.*?\]', body)[0]
cids = re.findall(r'(?<="cid":)\d*', pages)
log.info(f'{cids=}')
# get post date
publish = re.findall(r'(?<=Published" content=")\d{4}-\d{2}-\d{2}', body)[0]
start_date = datetime.strptime(publish, '%Y-%m-%d')
log.info(f'{publish=}')
result = {}
while True:
date = start_date.strftime('%Y-%m-%d')
log.info(f'get danmaku of {date}')
for cid in cids:
dms = get_history_danmaku(cid, date) # get danmaku
for dm in dms: # format data
dmid = dm['dmid']
result.setdefault(dmid, dm) # 防止重复添加
# go next day or exit
start_date += timedelta(1)
if start_date > datetime.now():
break
here = os.path.abspath(os.path.dirname(__file__))
output = os.path.join(here, f'av{aid}_dm.json')
with open(output, 'w', encoding='utf-8') as f:
f.write(json.dumps(result, ensure_ascii=False, indent=2))
if __name__ == '__main__':
log.basicConfig(level=log.INFO)
aid = 79974337
get_all_history_danmaku(aid)
- 做广告的,代码比较菜,欢迎指正。
- 弹幕里有一个字段不知道怎么意思,有知道的请指教下。
- 其实评论的部分更好一些,直接关联到用户 aid,可以做得更深一点。那个我们搞过现成的轮子。
- 不过写完就觉得没必要在这破事儿上费太多功夫,纯分享了。