基于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 socket多线程通讯实例分析(聊天室)
Apr 06 Python
django使用图片延时加载引起后台404错误
Apr 18 Python
一百多行python代码实现抢票助手
Sep 25 Python
Linux 修改Python命令的方法示例
Dec 03 Python
Python数据可视化教程之Matplotlib实现各种图表实例
Jan 13 Python
python统计中文字符数量的两种方法
Jan 31 Python
Python 正则表达式爬虫使用案例解析
Sep 23 Python
Python continue语句实例用法
Feb 06 Python
python名片管理系统开发
Jun 18 Python
Python高阶函数与装饰器函数的深入讲解
Nov 10 Python
python 实现全球IP归属地查询工具
Dec 18 Python
python 爬取哔哩哔哩up主信息和投稿视频
Jun 07 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 Try Catch异常测试
2009/03/01 PHP
php 购物车实例(申精)
2009/05/11 PHP
codeigniter框架批量插入数据
2014/01/09 PHP
PHP冒泡算法详解(递归实现)
2014/11/10 PHP
php模拟服务器实现autoindex效果的方法
2015/03/10 PHP
PHP异常处理浅析
2015/05/12 PHP
简单的php+mysql聊天室实现方法(附源码)
2016/01/05 PHP
thinkPHP5.0框架开发规范简介
2017/03/25 PHP
PHP实现的微信公众号扫码模拟登录功能示例
2019/05/30 PHP
javascript 日历提醒系统( 兼容所有浏览器 )
2009/04/07 Javascript
javascript怎么禁用浏览器后退按钮
2014/03/27 Javascript
JavaScript中的类数组对象介绍
2014/12/30 Javascript
浅谈JS继承_寄生式继承 & 寄生组合式继承
2016/08/16 Javascript
jQuery ajax 当async为false时解决同步操作失败的问题
2016/11/18 Javascript
JS实现焦点图轮播效果的方法详解
2016/12/19 Javascript
Angular+Bootstrap+Spring Boot实现分页功能实例代码
2017/07/21 Javascript
原生JS实现的简单小钟表功能示例
2018/08/30 Javascript
JS实现盒子跟着鼠标移动及键盘方向键控制盒子移动效果示例
2019/01/29 Javascript
JavaScript实现获取两个排序数组的中位数算法示例
2019/02/26 Javascript
vue 实现input表单元素的disabled示例
2019/10/28 Javascript
js基于canvas实现时钟组件
2021/02/07 Javascript
[01:22:42]2014 DOTA2华西杯精英邀请赛 5 24 DK VS LGD
2014/05/26 DOTA
python redis 删除key脚本的实例
2019/02/19 Python
Python中numpy模块常见用法demo实例小结
2019/03/16 Python
Python中使用双下划线防止类属性被覆盖问题
2019/06/27 Python
python3实现猜数字游戏
2020/12/07 Python
Python中pymysql 模块的使用详解
2019/08/12 Python
canvas实现有递增动画的环形进度条的实现方法
2019/07/10 HTML / CSS
html5使用canvas画三角形
2014/12/15 HTML / CSS
HTML5拖拽的简单实例
2016/05/30 HTML / CSS
阿巴庭院:Abba Patio
2019/06/18 全球购物
个人简历自我鉴定
2013/10/11 职场文书
高中英语演讲稿范文
2014/04/24 职场文书
土木工程专业本科生求职信
2014/10/01 职场文书
《黑岩★★射手 DAWN FALL》BD发售宣传CM公开
2022/04/04 日漫
win10忘记pin密码登录不了怎么办?win10忘记pin密码登不进去的解决方法
2022/07/07 数码科技