목차
回复内容:
백엔드 개발 파이썬 튜토리얼 如何获取斗鱼直播间的弹幕信息?

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

Jun 06, 2016 pm 04:11 PM

如何获取如图红色框中的弹幕信息呢?想做一些基于弹幕信息的二次开发。


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

回复内容:

在参考顶楼的回答和评论后,正确获取到了弹幕,来回报下社会,代码已经放在Github上了! douyu/danmu.cc at master · fishioon/douyu · GitHub
代码是C写的,本来用的python,感觉C更好用(在处理数据的时候)。

比较喜欢看yyf的dota2直播,但是最近yyf经常吹B,说有网友弹幕问“枫哥枫哥,你的XX怎么这么厉害啊”,水友们纷纷表示不信,所以就想着把弹幕爬下来,同时还有那些说赢了直播吃翔的,我通通都要记录下来!!!

回答正题,那我们该如何弄清楚这个协议呢?
弹幕属于实时消息,第一反应应该用websocket实现,打开chrome,F12,websocket中竟然找不到!那估计是通过Flash实现了。前端不熟,找了半天也没找到JS实现代码,只好祭出wireshark来分析了。
看了顶楼的提示,在wireshark中查看端口为8601的数据包,如下图所示。
如何获取斗鱼直播间的弹幕信息?
前三个数据包就是TCP的三次握手啦,复习下;接着我们看第四个数据包,如下图所示
如何获取斗鱼直播间的弹幕信息?一般来说通信协议设计“内容长度”+“内容”,我们来看tcp数据包内容,前四个字节为0x59 = 5*16+9 = 89,再看整个数据包长度为93,正好符合长度+内容,差不多我们可以确定通信协议如下:
struct {
int len; //数据包长度
int code; //经抓包发现该字段一直与len字段一致
int magic; //不知道啥意思,发现请求都是0x2b1, 返回都是0x2b2
char content[0]; //消息具体内容
}
从图中的内容中可以看到:
1. 登录弹幕服务器: "type@=loginreq/username@%s=/password@=%s/roomid@=%d/ct@=2/",输入自己的账号密码(经测试发现,账号密码随便填都能成功),要看的房间id,如yyf的房间id为52428
通过socket发送上面的内容后,你回收到这样的一条数据,格式与发送格式一样:
“type@=loginres/userid@=0/roomgroup@=0/pg@=0/sessionid@=0/username@=/nickname@=/live_stat@=0/is_illegal@=0/npv@=0/best_dlev@=0/cur_lev@=0/”,没发现有啥有用的数据。
2. 收到上面的消息后,这时候要加入一个组,格式如下:
"type@=joingroup/rid@=%d/gid@=%d/",rid就是房间id,要注意的问题来了:
gid应该是group id,登录不同房间该id都不一样,每次我都是抓包来查看该id是多少,有知情人告诉我吗?(一楼评论中也提到这个问题)
发送上面的消息后,我们就可以安心的接收数据了,然后从数据中提取我们想要的就可以了,其中很多数据都不懂啥意思。
最后我们看下yyf房间的弹幕哈!(节奏带的飞起)
如何获取斗鱼直播间的弹幕信息? Update 20160214 : 更新Python和Ruby客户端(请大家不要问我为什么情人节这一天为什么闲着没事更新代码)
Update 20160220 : 更新Python客户端,增加直播视频的Live获取,以及Mac平台下面的Mplayer的视频播放.代码均放在Github上面. GitHub - twocucao/danmu.fm: douyutv danmu 斗鱼TV 弹幕助手

由于zhihu没有法子贴动态图,那只好移步到我的博客一看了.(看博客之前记得点赞╮(╯_╰)╭)

Python程序员如何优雅的看斗鱼TV

===================优雅的看斗鱼TV的分割线==================================

-1.如果不想看长文,直接使用.则在安装好Python3或者Ruby2.0以上版本.

<span class="c">#安装Python客户端</span>
pip3 install danmu.fm

<span class="c"># 比如主播的直播间</span>
danmu.fm http://www.douyutv.com/16789
<span class="c">#或者</span>
danmu.fm 16789
<span class="c">#安装Ruby客户端</span>
gem install danmu
<span class="c">#使用</span>
danmu douyu <span class="o">[</span>room_id/url<span class="o">]</span>
<span class="c">#比如</span>
danmu douyu qiuri
danmu douyu http://www.douyutv.com/13861
로그인 후 복사
[多图预警]

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在线编辑
就变成这样:
<span class="p">[{</span><span class="nt">"ip"</span><span class="p">:</span><span class="s2">"119.90.49.107"</span><span class="p">,</span><span class="nt">"port"</span><span class="p">:</span><span class="s2">"8035"</span><span class="p">},{</span><span class="nt">"ip"</span><span class="p">:</span><span class="s2">"119.90.49.102"</span><span class="p">,</span><span class="nt">"port"</span><span class="p">:</span><span class="s2">"8008"</span><span class="p">},{</span><span class="nt">"ip"</span><span class="p">:</span><span class="s2">"119.90.49.110"</span><span class="p">,</span><span class="nt">"port"</span><span class="p">:</span><span class="s2">"8050"</span><span class="p">},{</span><span class="nt">"ip"</span><span class="p">:</span><span class="s2">"119.90.49.104"</span><span class="p">,</span><span class="nt">"port"</span><span class="p">:</span><span class="s2">"8020"</span><span class="p">},{</span><span class="nt">"ip"</span><span class="p">:</span><span class="s2">"119.90.49.107"</span><span class="p">,</span><span class="nt">"port"</span><span class="p">:</span><span class="s2">"8034"</span><span class="p">},{</span><span class="nt">"ip"</span><span class="p">:</span><span class="s2">"119.90.49.92"</span><span class="p">,</span><span class="nt">"port"</span><span class="p">:</span><span class="s2">"8059"</span><span class="p">},{</span><span class="nt">"ip"</span><span class="p">:</span><span class="s2">"119.90.49.95"</span><span class="p">,</span><span class="nt">"port"</span><span class="p">:</span><span class="s2">"8071"</span><span class="p">},{</span><span class="nt">"ip"</span><span class="p">:</span><span class="s2">"119.90.49.101"</span><span class="p">,</span><span class="nt">"port"</span><span class="p">:</span><span class="s2">"8001"</span><span class="p">},{</span><span class="nt">"ip"</span><span class="p">:</span><span class="s2">"119.90.49.93"</span><span class="p">,</span><span class="nt">"port"</span><span class="p">:</span><span class="s2">"8063"</span><span class="p">},{</span><span class="nt">"ip"</span><span class="p">:</span><span class="s2">"119.90.49.91"</span><span class="p">,</span><span class="nt">"port"</span><span class="p">:</span><span class="s2">"8053"</span><span class="p">}]</span>
로그인 후 복사
##################20160325更新##########################
最近斗鱼修改了弹幕格式,大概长这个样子
<span class="n">b</span><span class="s">'</span><span class="se">\x81\x00\x00\x00\x81\x00\x00\x00\xb2\x02\x00\x00</span><span class="s">type@=chatmsg/rid@=9401/uid@=12635840/nn@=</span><span class="se">\xe8\xb6\x85\xe8\xb6\x8a\xe7\xa5\x9e\xe7\x9a\x84</span><span class="s">boy/txt@=</span><span class="se">\xe6\x89\x93\xe8\x84\xb8\xe5\x90\xa7</span><span class="s">/cid@=20e4e3fe427e410c67c5010000000000/level@=5/</span><span class="se">\x00</span><span class="s">'</span>
로그인 후 복사
优雅的获取弹幕和看弹幕:

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

随便抓了100个房间大概半小时。
优雅的抓出那些说“屎尿屁”的“精神周星驰”:
(那么大家都发现了,疯狂说这些一般都是20级以下的人。斗鱼要到20级大概是充值3000-4000左右好像。那么你们明白什么了吗)
如何获取斗鱼直播间的弹幕信息?如何获取斗鱼直播间的弹幕信息?如何获取斗鱼直播间的弹幕信息?如何获取斗鱼直播间的弹幕信息?

最后还有更好玩的(大家来找壕,看看壕都喜欢去什么房间):
如何获取斗鱼直播间的弹幕信息?






















当然编程的方式也要优雅:Python

至于方法,最高赞已经很干净清晰了的解答了,我这里做小小补充。

其实不需要那么多工序,用socket直接3个命令就可以了:

下面伪代码:

client_danmu = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#在客户端开启心跳维护
client_danmu.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) 


#官方弹幕服务器'openbarrage.douyutv.com'
SERVER = socket.gethostbyname('openbarrage.douyutv.com')
PORT = 8601

client_danmu.connect((SERVER,PORT))
client_danmu.settimeout(2)    #记得设置延迟,不然卡着recv

#这里发的要处理下发送内容,用最高赞的方法获取封包格式就好了
封包1 = 'type@=loginreq/username@=visitor1234567/password@=/roomid@=房间号/'
#登陆弹幕服务器
client_danmu.send(封包1)

封包2 =  'type@=joingroup/rid@=房间号/gid@=-9999/'
#加入弹幕组,这里要注意,gid就是弹幕组号。-9999是斗鱼开放的第三方获取弹幕的组别。是能获取所有弹幕的。因为有些主播动辄几十万人,那弹幕量如果都发给所有用户,那卡死用户事小,斗鱼自己流量事大啊。所以一般都是分组发送,所以你平时在浏览器看的并不一定是所有弹幕。用-9999这个组别号是可以获取所有的
client_danmu.send(封包2)

#这里开始就是用while循环获取弹幕了,记得大概每30秒发一个心跳包过去。
封包3 =  'type@=mrkl/'
client_danmu.send(封包3)
로그인 후 복사
那我说说?
是这样的,斗鱼的弹幕信息有个自己的服务器
danmu.douyutv.com 可以抓包看到,他通过TCP连接到斗鱼弹幕服务器,然后获取的信息,那么想要对它进行二次开发只需要模拟用户连接并登入弹幕服务器即可。
 弹幕连接 OnConn
(program):1  弹幕 UserLogin [type@=loginreq/username@=xxxx/password@=1234567890123456/roomid@=58718/]
(program):1 弹幕 网络数据 [type@=loginres/userid@=0/roomgroup@=67108896/pg@=0/sessionid@=6/username@=/nickname@=/is_signined@=432003648/signin_count@=32756/s@=% ô/live_stat@=125387584/npv@=32756/]
(program):1 弹幕登录成功
VM160:1 弹幕分组 [type@=joingroup/rid@=58718/gid@=0/]
2VM171:1 FMPNetStream连接状态:NetStream.Buffer.Full
VM175:1 弹幕 网络数据 [type@=userenter/rid@=58718/gid@=0/userinfo@=id@A=4295897@Sname@A=auto_DJUziSYiJo@Snick@A=芙苏不语丶怪力乱神@Srg@A=1@Spg@A=1@Srt@A=1416480352@Sbg@A=0@Sweight@A=12800@Sstrength@A=51800@Scps_id@A=0@Sps@A=1@Sver@A=0@Sm_deserve_lev@A=0@S/]
VM176:1 新用户进入信息: [id@=4295897/name@=auto_DJUziSYiJo/nick@=芙苏不语丶怪力乱神/rg@=1/bg@=0/pg@=1/rt@=1416480352/weight@=12800/strength@=51800/cps_id@=0/]
로그인 후 복사
我记录了下抓取弹幕的流程,可以参考下。
地址: 斗鱼弹幕抓取
代码:github.com/ndrlslz/Douy 既然没人发nodejs版,那我就发一个吧
<span class="kd">var</span> <span class="nx">net</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'net'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">uuid</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'node-uuid'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">md5</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'md5'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">request</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'request'</span><span class="p">);</span>

<span class="kd">var</span> <span class="nx">HOST</span> <span class="o">=</span> <span class="s1">'danmu.douyutv.com'</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">PORT</span> <span class="o">=</span> <span class="mi">8602</span><span class="p">;</span>

<span class="kd">function</span> <span class="nx">send</span><span class="p">(</span><span class="nx">socket</span><span class="p">,</span> <span class="nx">payload</span><span class="p">)</span>
<span class="p">{</span>	
	<span class="kd">var</span> <span class="nx">data</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Buffer</span><span class="p">(</span><span class="mi">4</span> <span class="o">+</span> <span class="mi">4</span> <span class="o">+</span> <span class="mi">4</span> <span class="o">+</span> <span class="nx">payload</span><span class="p">.</span><span class="nx">length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
	<span class="nx">data</span><span class="p">.</span><span class="nx">writeInt32LE</span><span class="p">(</span><span class="mi">4</span> <span class="o">+</span> <span class="mi">4</span> <span class="o">+</span> <span class="nx">payload</span><span class="p">.</span><span class="nx">length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">//length</span>
	<span class="nx">data</span><span class="p">.</span><span class="nx">writeInt32LE</span><span class="p">(</span><span class="mi">4</span> <span class="o">+</span> <span class="mi">4</span> <span class="o">+</span> <span class="nx">payload</span><span class="p">.</span><span class="nx">length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span> <span class="c1">//code</span>
	<span class="nx">data</span><span class="p">.</span><span class="nx">writeInt32LE</span><span class="p">(</span><span class="mh">0x000002b1</span><span class="p">,</span> <span class="mi">8</span><span class="p">);</span> <span class="c1">//magic</span>
	<span class="nx">data</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">payload</span><span class="p">,</span> <span class="mi">12</span><span class="p">);</span> <span class="c1">//payload</span>
	<span class="nx">data</span><span class="p">.</span><span class="nx">writeInt8</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">4</span> <span class="o">+</span> <span class="mi">4</span> <span class="o">+</span> <span class="mi">4</span> <span class="o">+</span> <span class="nx">payload</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span> <span class="c1">//end of string</span>
	<span class="nx">socket</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">login</span><span class="p">(</span><span class="nx">socket</span><span class="p">,</span> <span class="nx">roomid</span><span class="p">,</span> <span class="nx">user</span><span class="p">,</span> <span class="nx">password</span><span class="p">)</span>
<span class="p">{</span>
	<span class="kd">var</span> <span class="nx">req</span> <span class="o">=</span> <span class="s1">'type@=loginreq/username@='</span> <span class="o">+</span> <span class="nx">user</span> <span class="o">+</span> <span class="s1">'/password@='</span> <span class="o">+</span> <span class="nx">password</span> <span class="o">+</span> <span class="s1">'/roomid@='</span> <span class="o">+</span> <span class="nx">roomid</span><span class="p">;</span>
	<span class="nx">send</span><span class="p">(</span><span class="nx">socket</span><span class="p">,</span> <span class="nx">req</span><span class="p">);</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">getGroupServer</span><span class="p">(</span><span class="nx">roomid</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span>
<span class="p">{</span>
	<span class="nx">request</span><span class="p">({</span><span class="nx">uri</span><span class="o">:</span><span class="s1">'http://www.douyutv.com/'</span> <span class="o">+</span> <span class="nx">roomid</span><span class="p">},</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">resp</span><span class="p">,</span> <span class="nx">body</span><span class="p">)</span> <span class="p">{</span>
		<span class="kd">var</span> <span class="nx">server_config</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">body</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="sr">/room_args = (.*?)\}\;/g</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="nx">replace</span><span class="p">(</span><span class="s1">'room_args = '</span><span class="p">,</span> <span class="s1">''</span><span class="p">).</span><span class="nx">replace</span><span class="p">(</span><span class="s1">';'</span><span class="p">,</span> <span class="s1">''</span><span class="p">));</span>
		<span class="nx">server_config</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">unescape</span><span class="p">(</span><span class="nx">server_config</span><span class="p">[</span><span class="s1">'server_config'</span><span class="p">]));</span>
		<span class="nx">callback</span><span class="p">(</span><span class="nx">server_config</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">ip</span><span class="p">,</span> <span class="nx">server_config</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">port</span><span class="p">);</span>
	<span class="p">});</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">getGroupId</span><span class="p">(</span><span class="nx">roomid</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span>
<span class="p">{</span>
	<span class="kd">var</span> <span class="nx">rt</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">now</span><span class="p">;</span>
	<span class="kd">var</span> <span class="nx">devid</span> <span class="o">=</span> <span class="nx">uuid</span><span class="p">.</span><span class="nx">v4</span><span class="p">().</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/-/g</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
	<span class="kd">var</span> <span class="nx">vk</span> <span class="o">=</span> <span class="nx">md5</span><span class="p">(</span><span class="nx">rt</span> <span class="o">+</span> <span class="s1">'7oE9nPEG9xXV69phU31FYCLUagKeYtsF'</span> <span class="o">+</span> <span class="nx">devid</span><span class="p">)</span>
	<span class="kd">var</span> <span class="nx">req</span> <span class="o">=</span> <span class="s1">'type@=loginreq/username@=/password@=/roomid@='</span> <span class="o">+</span> 
		<span class="nx">roomid</span> <span class="o">+</span> <span class="s1">'/ct@=0/vk@='</span> <span class="o">+</span> <span class="nx">vk</span> <span class="o">+</span> <span class="s1">'/devid@='</span> <span class="o">+</span> 
		<span class="nx">devid</span> <span class="o">+</span> <span class="s1">'/rt@='</span> <span class="o">+</span> <span class="nx">rt</span> <span class="o">+</span> <span class="s1">'/ver=@20150929/'</span><span class="p">;</span>
	
	<span class="nx">getGroupServer</span><span class="p">(</span><span class="nx">roomid</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">server</span><span class="p">,</span> <span class="nx">port</span><span class="p">)</span> <span class="p">{</span>
		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'group server: '</span> <span class="o">+</span> <span class="nx">server</span> <span class="o">+</span> <span class="s1">':'</span> <span class="o">+</span> <span class="nx">port</span><span class="p">);</span>
		<span class="kd">var</span> <span class="nx">socket</span> <span class="o">=</span> <span class="nx">net</span><span class="p">.</span><span class="nx">connect</span><span class="p">(</span><span class="nx">port</span><span class="p">,</span> <span class="nx">server</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
			<span class="nx">send</span><span class="p">(</span><span class="nx">socket</span><span class="p">,</span> <span class="nx">req</span><span class="p">);</span>
		<span class="p">});</span>
		
		<span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'data'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
			<span class="k">if</span> <span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'type@=setmsggroup'</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
				<span class="kd">var</span> <span class="nx">gid</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">().</span><span class="nx">match</span><span class="p">(</span><span class="sr">/gid@=(.*?)\//g</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="nx">replace</span><span class="p">(</span><span class="s1">'gid@='</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
				<span class="nx">gid</span> <span class="o">=</span> <span class="nx">gid</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">gid</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
				<span class="nx">socket</span><span class="p">.</span><span class="nx">destroy</span><span class="p">();</span>
				<span class="nx">callback</span><span class="p">(</span><span class="nx">gid</span><span class="p">);</span>
			<span class="p">}</span>
		<span class="p">});</span>	
	<span class="p">});</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">monitorRoom</span><span class="p">(</span><span class="nx">roomid</span><span class="p">)</span>
<span class="p">{</span>
	<span class="kd">var</span> <span class="nx">socket</span> <span class="o">=</span> <span class="nx">net</span><span class="p">.</span><span class="nx">connect</span><span class="p">(</span><span class="nx">PORT</span><span class="p">,</span> <span class="nx">HOST</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
		<span class="nx">login</span><span class="p">(</span><span class="nx">socket</span><span class="p">,</span> <span class="s1">'visitor1234567'</span><span class="p">,</span> <span class="s1">'1234567890123456'</span><span class="p">);</span>
	<span class="p">});</span>
	
	<span class="nx">setInterval</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
		<span class="nx">send</span><span class="p">(</span><span class="nx">socket</span><span class="p">,</span> <span class="s1">'type@=keeplive/tick@=70/'</span><span class="p">);</span> <span class="c1">//send keep alive message repeatly</span>
	<span class="p">},</span> <span class="mi">50000</span><span class="p">);</span>
	
	<span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'data'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
		<span class="c1">//data is a Buffer here</span>
		<span class="k">if</span> <span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'type@=loginres'</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
			<span class="nx">getGroupId</span><span class="p">(</span><span class="nx">roomid</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">gid</span><span class="p">)</span> <span class="p">{</span>
				<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'gid of room['</span> <span class="o">+</span> <span class="nx">roomid</span> <span class="o">+</span><span class="s1">'] is '</span> <span class="o">+</span> <span class="nx">gid</span><span class="p">)</span>
				<span class="nx">send</span><span class="p">(</span><span class="nx">socket</span><span class="p">,</span> <span class="s1">'type@=joingroup/rid@='</span> <span class="o">+</span> <span class="nx">roomid</span> <span class="o">+</span> <span class="s1">'/gid@='</span> <span class="o">+</span> <span class="nx">gid</span> <span class="o">+</span> <span class="s1">'/'</span><span class="p">);</span>
			<span class="p">});</span>
		<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'type@=chatmessage'</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
			<span class="kd">var</span> <span class="nx">msg</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">();</span>
			<span class="kd">var</span> <span class="nx">snick</span> <span class="o">=</span> <span class="nx">msg</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="sr">/snick@=(.*?)\//g</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="nx">replace</span><span class="p">(</span><span class="s1">'snick@='</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
			<span class="kd">var</span> <span class="nx">content</span> <span class="o">=</span> <span class="nx">msg</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="sr">/content@=(.*?)\//g</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="nx">replace</span><span class="p">(</span><span class="s1">'content@='</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
			
			<span class="nx">snick</span> <span class="o">=</span> <span class="nx">snick</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">snick</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
			<span class="nx">content</span> <span class="o">=</span> <span class="nx">content</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">content</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
			<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">snick</span> <span class="o">+</span> <span class="s1">': '</span> <span class="o">+</span> <span class="nx">content</span><span class="p">);</span><span class="c1">// 弹幕</span>
		<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'type@=userenter'</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span> <span class="o">||</span>
			<span class="nx">data</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'type@=keeplive'</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span> <span class="o">||</span>
			<span class="nx">data</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'type@=dgn/gfid@=131'</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span> <span class="o">||</span>
			<span class="nx">data</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'type@=blackres'</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span> <span class="o">||</span>
			<span class="nx">data</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'type@=dgn/gfid@=129'</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span> <span class="o">||</span> 
			<span class="nx">data</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'type@=upgrade'</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span> <span class="o">||</span>
			<span class="nx">data</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'type@=ranklist'</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span> <span class="o">||</span>
			<span class="nx">data</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'type@=onlinegift'</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
			<span class="c1">//没用的消息</span>
		<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'type@=spbc'</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
			<span class="kd">var</span> <span class="nx">drid</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">().</span><span class="nx">match</span><span class="p">(</span><span class="sr">/drid@=(.*?)\//g</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="nx">replace</span><span class="p">(</span><span class="s1">'drid@='</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
			<span class="nx">drid</span> <span class="o">=</span> <span class="nx">drid</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">drid</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
			
			<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'rocket! room id:'</span> <span class="o">+</span> <span class="nx">drid</span><span class="p">);</span>
		<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
			<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>	<span class="c1">//在这里显示其它类型的消息</span>
		<span class="p">}</span>
	<span class="p">});</span>
<span class="p">}</span>

<span class="nx">monitorRoom</span><span class="p">(</span><span class="s1">'<这里填roomid>'</span><span class="p">);</span>
로그인 후 복사
以前我们是做视频聊天站的。2014年8月-9月我们一个月的时间抄了一个斗鱼,没错是整个站。开始的时候由于内容上的高度重合,比如蜡笔小新、RM等,房间也没有人气,我将斗鱼某房间的弹幕扒下来转播到对应内容的房间中,并过滤掉一些关键字,足以以假乱真。虽然平台最终半死不活,且『技术本身并不可耻』,然而还是匿了。

技术核心我看大家都没答到一点,就是反编译flash播放器,因为所有与socket相关的实现都在flash里,反编译出源码后的逻辑、协议,一目了然,然后用python实现出来,很简单,不上码了。

这问题应该是纯技术交流吧,我这么想。 斗鱼已经开放第三方接口了,获取弹幕的流程变得简单了许多:
《斗鱼弹幕服务器第三方接入协议v1.4.1》发布信息 斗鱼开发者论坛
以下为大概流程
第三方接入弹幕服务器:
IP 地址:openbarrage.douyutv.com 端口:8601
1.客户端向服务器端发送登录请求,格式为;
type@=loginreq/roomid@=****/
로그인 후 복사
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

<gum> : Bubble Gum Simulator Infinity- 로얄 키를 얻고 사용하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
Nordhold : Fusion System, 설명
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora : 마녀 트리의 속삭임 - Grappling Hook 잠금 해제 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Python vs. C : 응용 및 사용 사례가 비교되었습니다 Python vs. C : 응용 및 사용 사례가 비교되었습니다 Apr 12, 2025 am 12:01 AM

Python은 데이터 과학, 웹 개발 및 자동화 작업에 적합한 반면 C는 시스템 프로그래밍, 게임 개발 및 임베디드 시스템에 적합합니다. Python은 단순성과 강력한 생태계로 유명하며 C는 고성능 및 기본 제어 기능으로 유명합니다.

파이썬 : 게임, Guis 등 파이썬 : 게임, Guis 등 Apr 13, 2025 am 12:14 AM

Python은 게임 및 GUI 개발에서 탁월합니다. 1) 게임 개발은 Pygame을 사용하여 드로잉, 오디오 및 기타 기능을 제공하며 2D 게임을 만드는 데 적합합니다. 2) GUI 개발은 Tkinter 또는 PYQT를 선택할 수 있습니다. Tkinter는 간단하고 사용하기 쉽고 PYQT는 풍부한 기능을 가지고 있으며 전문 개발에 적합합니다.

Python vs. C : 학습 곡선 및 사용 편의성 Python vs. C : 학습 곡선 및 사용 편의성 Apr 19, 2025 am 12:20 AM

Python은 배우고 사용하기 쉽고 C는 더 강력하지만 복잡합니다. 1. Python Syntax는 간결하며 초보자에게 적합합니다. 동적 타이핑 및 자동 메모리 관리를 사용하면 사용하기 쉽지만 런타임 오류가 발생할 수 있습니다. 2.C는 고성능 응용 프로그램에 적합한 저수준 제어 및 고급 기능을 제공하지만 학습 임계 값이 높고 수동 메모리 및 유형 안전 관리가 필요합니다.

파이썬과 시간 : 공부 시간을 최대한 활용 파이썬과 시간 : 공부 시간을 최대한 활용 Apr 14, 2025 am 12:02 AM

제한된 시간에 Python 학습 효율을 극대화하려면 Python의 DateTime, Time 및 Schedule 모듈을 사용할 수 있습니다. 1. DateTime 모듈은 학습 시간을 기록하고 계획하는 데 사용됩니다. 2. 시간 모듈은 학습과 휴식 시간을 설정하는 데 도움이됩니다. 3. 일정 모듈은 주간 학습 작업을 자동으로 배열합니다.

Python vs. C : 성능과 효율성 탐색 Python vs. C : 성능과 효율성 탐색 Apr 18, 2025 am 12:20 AM

Python은 개발 효율에서 C보다 낫지 만 C는 실행 성능이 높습니다. 1. Python의 간결한 구문 및 풍부한 라이브러리는 개발 효율성을 향상시킵니다. 2.C의 컴파일 유형 특성 및 하드웨어 제어는 실행 성능을 향상시킵니다. 선택할 때는 프로젝트 요구에 따라 개발 속도 및 실행 효율성을 평가해야합니다.

Python Standard Library의 일부는 무엇입니까? 목록 또는 배열은 무엇입니까? Python Standard Library의 일부는 무엇입니까? 목록 또는 배열은 무엇입니까? Apr 27, 2025 am 12:03 AM

Pythonlistsarepartoftsandardlardlibrary, whileraysarenot.listsarebuilt-in, 다재다능하고, 수집 할 수있는 반면, arraysarreprovidedByTearRaymoduledlesscommonlyusedDuetolimitedFunctionality.

Python 학습 : 2 시간의 일일 연구가 충분합니까? Python 학습 : 2 시간의 일일 연구가 충분합니까? Apr 18, 2025 am 12:22 AM

하루에 2 시간 동안 파이썬을 배우는 것으로 충분합니까? 목표와 학습 방법에 따라 다릅니다. 1) 명확한 학습 계획을 개발, 2) 적절한 학습 자원 및 방법을 선택하고 3) 실습 연습 및 검토 및 통합 연습 및 검토 및 통합,이 기간 동안 Python의 기본 지식과 고급 기능을 점차적으로 마스터 할 수 있습니다.

파이썬 : 자동화, 스크립팅 및 작업 관리 파이썬 : 자동화, 스크립팅 및 작업 관리 Apr 16, 2025 am 12:14 AM

파이썬은 자동화, 스크립팅 및 작업 관리가 탁월합니다. 1) 자동화 : 파일 백업은 OS 및 Shutil과 같은 표준 라이브러리를 통해 실현됩니다. 2) 스크립트 쓰기 : PSUTIL 라이브러리를 사용하여 시스템 리소스를 모니터링합니다. 3) 작업 관리 : 일정 라이브러리를 사용하여 작업을 예약하십시오. Python의 사용 편의성과 풍부한 라이브러리 지원으로 인해 이러한 영역에서 선호하는 도구가됩니다.

See all articles