基于asyncio 异步协程框架实现收集B站直播弹幕


Posted in Python onSeptember 11, 2016

前言

虽然标题是全站,但目前只做了等级 top 100 直播间的全天弹幕收集。

弹幕收集系统基于之前的B 站直播弹幕姬 Python 版修改而来。具体协议分析可以看上一篇文章。

直播弹幕协议是直接基于 TCP 协议,所以如果 B 站对类似我这种行为做反制措施,比较困难。应该有我不知道的技术手段来检测类似我这种恶意行为。

我试过同时连接 100 个房间,和连接单个房间 100 次的实验,都没有问题。>150 会被关闭链接。

直播间的选取

现在弹幕收集系统在选取直播间上比较简单,直接选取了等级 top100。

以后会修改这部分,改成定时去 http://live.bilibili.com/all 查看新开播的直播间,并动态添加任务。

异步任务和弹幕存储

收集系统仍旧使用了 asyncio 异步协程框架,对于每一个直播间都使用如下方法来加进 loop 中。

danmuji = bilibiliClient(url, self.lock, self.commentq, self.numq)
task1 = asyncio.ensure_future(danmuji.connectServer())
task2 = asyncio.ensure_future(danmuji.HeartbeatLoop())

其实若将心跳任务 HeartbeatLoop 放入 connectorServer 中去启动,代码看起来更优雅一些。但这么做是因为我需要维护一个任务列表,后面会有描述。

在弹幕存储上我花了些时间选择。

数据库存储是一个同步 IO 的过程,Insert 的时候会阻塞弹幕收集的任务。虽然有 aiomysql 这种异步接口,但配置数据库太麻烦,我的设想是这个小系统能够方便地部署。

最终我选择使用自带的 sqlite3。但 sqlite3 无法做并行操作,故开了一个线程单独进行数据库存储。在另一个线程中,100 * 2 个任务搜集所有的弹幕、人数信息,并塞进队列 commentq, numq 中。存储线程每隔 10s 唤醒一次,将队列中的数据写进 sqlite3 中,并清空队列。

在多线程和异步的配合下,网络流量没有被阻塞。

可能的连接失败场景处理

弹幕协议是直接基于 TCP,位与位直接关联性较强,一旦解析错误,很容易就抛 Exception(个人感觉,虽然 TCP 是可靠传输,但B站服务器自身发生错误也是有可能的)。所以有必要设计一个自动重连机制。

在 asyncio 文档中提到,

Done means either that a result / exception are available, or that the future was cancelled.

函数正常返回、抛出异常或者是被 cancel,都会退出当前任务。可以使用 done() 来判断。

每一个直播间对应两个任务,解析任务是最容易挂的,但并不会影响心跳任务,所以必须找出并将对应心跳任务结束。
在创建任务的时候使用字典记录每个房间的两个任务,

self.tasks[url] = [task1, task2]

在运行过程中,每隔 10s 做一次检查,

for url in self.tasks:
  item = self.tasks[url]
  task1 = item[0]
  task2 = item[1]
  if task1.done() == True or task2.done() == True:
    if task1.done() == False:
      task1.cancel()
    if task2.done() == False:
      task2.cancel()
    danmuji = bilibiliClient(url, self.lock, self.commentq, self.numq)
    task11 = asyncio.ensure_future(danmuji.connectServer())
    task22 = asyncio.ensure_future(danmuji.HeartbeatLoop())
    self.tasks[url] = [task11, task22]

实际我只见过一次任务失败的场景,是因为主播房间被封了,导致无法进入直播间。

结论

  1. B站人数是按照连接弹幕服务器的链接数量统计的。通过操纵链接量,可以瞬间增加任意人数观看,有商机?
  2. 运行的这几天中,发现即使大部分房间不在直播,也能有 >5 的人数,包括凌晨。我只能猜测也有和我一样的人在 24h 收集弹幕。
  3. top100 平均一天 40M 弹幕数据。
  4. 收集的弹幕能做什么?还没想好,可能可以拿来做用户行为分析 -_^

最后附上本源码的GITHUB地址 https://github.com/lyyyuna/bilibili_danmu_colloector

Python 相关文章推荐
使用Python实现下载网易云音乐的高清MV
Mar 16 Python
python实现的DES加密算法和3DES加密算法实例
Jun 03 Python
python DataFrame获取行数、列数、索引及第几行第几列的值方法
Apr 08 Python
TensorFlow 滑动平均的示例代码
Jun 19 Python
使用Django开发简单接口实现文章增删改查
May 09 Python
Python函数中的可变长参数详解
Sep 12 Python
django商品分类及商品数据建模实例详解
Jan 03 Python
python实现ftp文件传输系统(案例分析)
Mar 20 Python
Python通过len函数返回对象长度
Oct 22 Python
python opencv常用图形绘制方法(线段、矩形、圆形、椭圆、文本)
Apr 12 Python
利用Python判断你的密码难度等级
Jun 02 Python
Python 数据结构之十大经典排序算法一文通关
Oct 16 Python
asyncio 的 coroutine对象 与 Future对象使用指南
Sep 11 #Python
Python中使用asyncio 封装文件读写
Sep 11 #Python
Python 如何访问外围作用域中的变量
Sep 11 #Python
Python优化技巧之利用ctypes提高执行速度
Sep 11 #Python
Python 中的with关键字使用详解
Sep 11 #Python
Python冒泡排序注意要点实例详解
Sep 09 #Python
通过5个知识点轻松搞定Python的作用域
Sep 09 #Python
You might like
用libTemplate实现静态网页的生成
2006/10/09 PHP
PHP HTML代码串 截取实现代码
2009/06/29 PHP
PHP转换文件夹下所有文件编码的实现代码
2013/06/06 PHP
php获取textarea的值并处理回车换行的方法
2014/10/20 PHP
jQuery 学习入门篇附实例代码
2010/03/16 Javascript
window.onresize 多次触发的解决方法
2013/11/08 Javascript
iframe子页面与父页面在同域或不同域下的js通信
2014/05/07 Javascript
javaScript中两个等于号和三个等于号之间的区别介绍
2014/06/27 Javascript
JavaScript操作Cookie详解
2015/02/28 Javascript
jQuery插件datalist实现很好看的input下拉列表
2015/07/14 Javascript
使用Function.apply()的参数数组化来提高 JavaScript程序性能的技巧
2015/12/23 Javascript
利用Javascript实现BMI计算器
2016/08/16 Javascript
基于jQuery实现表格的排序
2016/12/02 Javascript
Vue + Webpack + Vue-loader学习教程之相关配置篇
2017/03/14 Javascript
jquery基于layui实现二级联动下拉选择(省份城市选择)
2017/06/20 jQuery
JS判断非空至少输入两个字符的简单实现方法
2017/06/23 Javascript
实例教学如何写vue插件
2017/11/30 Javascript
Vue组件全局注册实现警告框的实例详解
2018/06/11 Javascript
js实现指定时间倒计时效果
2019/08/26 Javascript
Vue 自定义指令功能完整实例
2019/09/17 Javascript
python发送伪造的arp请求
2014/01/09 Python
Python 序列化 pickle/cPickle模块使用介绍
2014/11/30 Python
python中快速进行多个字符替换的方法小结
2016/12/15 Python
Python给你的头像加上圣诞帽
2018/01/04 Python
python操作mysql代码总结
2018/06/01 Python
opencv3/C++图像像素操作详解
2019/12/10 Python
python中有函数重载吗
2020/05/28 Python
Django xadmin安装及使用详解
2020/10/26 Python
python脚本定时发送邮件
2020/12/22 Python
Europcar美国/加拿大:预订汽车或卡车租赁服务
2018/11/13 全球购物
估算杭州有多少软件工程师
2015/08/11 面试题
优秀生推荐信范文
2013/11/28 职场文书
社区学习十八大感想
2014/01/22 职场文书
派出所班子党的群众路线对照检查材料思想汇报
2014/10/01 职场文书
初中信息技术教学反思
2016/02/16 职场文书
JS实现刷新网页后之前浏览位置保持不变示例详解
2022/08/14 Javascript