基于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通过字典dict判断指定键值是否存在的方法
Mar 21 Python
Python编程中的异常处理教程
Aug 21 Python
Python制作钉钉加密/解密工具
Dec 07 Python
Python爬虫框架Scrapy实例代码
Mar 04 Python
Linux下多个Python版本安装教程
Aug 15 Python
对python中的装包与解包实例详解
Aug 24 Python
Python实现TCP探测目标服务路由轨迹的原理与方法详解
Sep 04 Python
Python解析json代码实例解析
Nov 25 Python
new_zeros() pytorch版本的转换方式
Feb 18 Python
python调用百度AI接口实现人流量统计
Feb 03 Python
教你如何用Python实现人脸识别(含源代码)
Jun 23 Python
python机器学习Github已达8.9Kstars模型解释器LIME
Nov 23 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
PHP获取redis里不存在的6位随机数应用示例【设置24小时过时】
2017/06/07 PHP
PHP实现的redis主从数据库状态检测功能示例
2017/07/20 PHP
用Javascript实现UTF8编码转换成gb2312编码
2006/12/22 Javascript
Javascript实例教程(19) 使用HoTMetal(3)
2006/12/23 Javascript
一实用的实现table排序的Javascript类库
2007/09/12 Javascript
JavaScript 学习笔记(十五)
2010/01/28 Javascript
jquery+json实现的搜索加分页效果
2010/03/31 Javascript
深入理解JavaScript系列(12) 变量对象(Variable Object)
2012/01/16 Javascript
jquery.form.js用法之清空form的方法
2014/03/07 Javascript
使用Node.js实现一个简单的FastCGI服务器实例
2014/06/09 Javascript
js控住DOM实现发布微博效果
2016/08/30 Javascript
JS组件系列之MVVM组件构建自己的Vue组件
2017/04/28 Javascript
JS实现的简单表单验证功能完整实例
2017/10/14 Javascript
node使用Mongoose类库实现简单的增删改查
2018/11/08 Javascript
ES6知识点整理之Proxy的应用实例详解
2019/04/16 Javascript
vue data引入本地图片的两种方式小结
2019/11/13 Javascript
基于vue-cli3创建libs库的实现方法
2019/12/04 Javascript
原生js无缝轮播插件使用详解
2020/03/09 Javascript
[47:22]Mineski vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
[06:53]2018DOTA2国际邀请赛寻真——勇于创新的Vici Gaming
2018/08/14 DOTA
[01:07:46]完美世界DOTA2联赛循环赛 Magma vs IO BO2第二场 11.01
2020/11/02 DOTA
python 根据pid杀死相应进程的方法
2017/01/16 Python
Python列表list操作符实例分析【标准类型操作符、切片、连接字符、列表解析、重复操作等】
2017/07/24 Python
Python实现一个带权无回置随机抽选函数的方法
2019/07/24 Python
python函数定义和调用过程详解
2020/02/09 Python
django自定义非主键自增字段类型详解(auto increment field)
2020/03/30 Python
在python下实现word2vec词向量训练与加载实例
2020/06/09 Python
conda安装tensorflow和conda常用命令小结
2021/02/20 Python
小学教师师德承诺书
2014/05/23 职场文书
2014年自愿离婚协议书范本
2014/09/25 职场文书
战略性融资合作协议书范本
2014/10/17 职场文书
2014年基层党支部工作总结
2014/12/04 职场文书
拾金不昧通报表扬范文
2015/05/05 职场文书
生鲜超市—未来中国最具有潜力零售业态
2019/08/02 职场文书
浅谈JavaScript作用域
2021/12/06 Javascript
2022年四月新番
2022/03/15 日漫