如何获取斗鱼直播间的弹幕信息?

如何获取如图红色框中的弹幕信息呢?想做一些基于弹幕信息的二次开发。
关注者
1011
被浏览
83080
[多图预警]

Update:2016.1.16
总结在博客里:抓取斗鱼直播弹幕
Github 项目地址:brucezz/DouyuCrawler
欢迎去提各种 issue & PR (代码水平不高)...


/********************************************************************************************/
Update:2016.1.14
最近几天会把 Java 项目发布到 Github 上面,大家提提意见 :)

/********************************************************************************************/
之前看到这个问题,感觉挺好玩的,就研究了下。
照着前面的思路,抓包分析。其他几位的回答,基本能抓到弹幕数据了,但是其中一个参数gid,需要手动抓包得到。我也查看了浏览器加载的js文件,没看到相关线索。最后看到排名第一的回答评论里有人说可以通过请求页面里server_config的ip。
然后我就顺着这条线索探索下去了。
具体过程如下:

先获取到直播页面中的server_config相关字段,发现是经过urlencode的。
然后进行urldecode,得到json数据,再格式化一下,
UrlEncode编码/UrlDecode解码
JSON在线编辑
就变成这样:
[{"ip":"119.90.49.107","port":"8035"},{"ip":"119.90.49.102","port":"8008"},{"ip":"119.90.49.110","port":"8050"},{"ip":"119.90.49.104","port":"8020"},{"ip":"119.90.49.107","port":"8034"},{"ip":"119.90.49.92","port":"8059"},{"ip":"119.90.49.95","port":"8071"},{"ip":"119.90.49.101","port":"8001"},{"ip":"119.90.49.93","port":"8063"},{"ip":"119.90.49.91","port":"8053"}]

用wireshark对以上几个端口进行监听,然后发现了几个相关的请求
前面三组四字节数据,就不解释了,前面的答案写的很清楚。
相关参数:
type@=loginreq/
username@=/
ct@=0/
password@=/
roomid@=25515/  #房间id
devid@=1C01371705D8B13361396AE2FAD50D6F/  #随机uuid 无连字符'-' 均为大写
rt@=1451848032/  #时间戳 单位为s
vk@=c2f6b956c37d8647a8f99abeeda0d568/  # 
ver@=20150929/.  #版本号
其中
vk的值也可以这样算(算出来的值和抓包请求的结果不同,但能通过服务器验证,没明白原理)
MD5(timestamp + "7oE9nPEG9xXV69phU31FYCLUagKeYtsF" + uuid)

至于中间那段字符串是什么鬼,我也没搞懂。这个算法是从github上的项目看到的https://github.com/reusu/DouyuAssistant

用代码也模拟请求任意一个地址即可,之后服务器会返回一串很长的数据,应该是几组返回数据合在了一起的,不过没啥影响
像这样:

返回的type为msgrepeaterlist,里面包含了一组可用的弹幕服务器,其实就是danmu.douyutv.com:8061 /8062 /12601 /12602 四个。数据里面带了一堆@符号是因为它进行了编码。在js里面发现的一段代码,转化为java代码 大概是这个样子:
    public static String deFilterStr(String str) {
        if (str == null) return null;
        return str.trim().replace("@A", "@").replace("@S", "/");
    }

    public static String filterStr(String str) {
        if (str == null) return null;
        return str.trim().replace("@", "@A").replace("/", "@S");
    }
然后decode出来,通过'/'字符可以分割成若干个用"@="连接的键值对。其实也可以用正则直接提取。

后面还有一条type为setmsggroup的数据,其中携带了gid参数,这个就是一直在寻找的groupid啦!

这个找到之后,后面就照着请求格式,登陆弹幕服务器


这样就请求完毕了,后面坐等服务器给你返回弹幕数据咯~~
弹幕数据包是这样子的(返回的参数倒是不少,主要就是content和snick两个):


还有一个地方,就是发送心跳包,类似这样

经过测试,只用发送type和tick时间戳就有效了。时间间隔的话,大概40s左右一次。

最终抓出来的就这样咯