찾다
백엔드 개발파이썬 튜토리얼如何获取斗鱼直播间的弹幕信息?

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


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

回复内容:

在参考顶楼的回答和评论后,正确获取到了弹幕,来回报下社会,代码已经放在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으로 문의하세요.
파이썬의 주요 목적 : 유연성과 사용 편의성파이썬의 주요 목적 : 유연성과 사용 편의성Apr 17, 2025 am 12:14 AM

Python의 유연성은 다중 파리가 지원 및 동적 유형 시스템에 반영되며, 사용 편의성은 간단한 구문 및 풍부한 표준 라이브러리에서 나옵니다. 유연성 : 객체 지향, 기능 및 절차 프로그래밍을 지원하며 동적 유형 시스템은 개발 효율성을 향상시킵니다. 2. 사용 편의성 : 문법은 자연 언어에 가깝고 표준 라이브러리는 광범위한 기능을 다루며 개발 프로세스를 단순화합니다.

파이썬 : 다목적 프로그래밍의 힘파이썬 : 다목적 프로그래밍의 힘Apr 17, 2025 am 12:09 AM

Python은 초보자부터 고급 개발자에 이르기까지 모든 요구에 적합한 단순성과 힘에 호의적입니다. 다목적 성은 다음과 같이 반영됩니다. 1) 배우고 사용하기 쉽고 간단한 구문; 2) Numpy, Pandas 등과 같은 풍부한 라이브러리 및 프레임 워크; 3) 다양한 운영 체제에서 실행할 수있는 크로스 플랫폼 지원; 4) 작업 효율성을 향상시키기위한 스크립팅 및 자동화 작업에 적합합니다.

하루 2 시간 안에 파이썬 학습 : 실용 가이드하루 2 시간 안에 파이썬 학습 : 실용 가이드Apr 17, 2025 am 12:05 AM

예, 하루에 2 시간 후에 파이썬을 배우십시오. 1. 합리적인 학습 계획 개발, 2. 올바른 학습 자원을 선택하십시오. 3. 실습을 통해 학습 된 지식을 통합하십시오. 이 단계는 짧은 시간 안에 Python을 마스터하는 데 도움이 될 수 있습니다.

Python vs. C : 개발자를위한 장단점Python vs. C : 개발자를위한 장단점Apr 17, 2025 am 12:04 AM

Python은 빠른 개발 및 데이터 처리에 적합한 반면 C는 고성능 및 기본 제어에 적합합니다. 1) Python은 간결한 구문과 함께 사용하기 쉽고 데이터 과학 및 웹 개발에 적합합니다. 2) C는 고성능과 정확한 제어를 가지고 있으며 게임 및 시스템 프로그래밍에 종종 사용됩니다.

파이썬 : 시간 약속과 학습 속도파이썬 : 시간 약속과 학습 속도Apr 17, 2025 am 12:03 AM

Python을 배우는 데 필요한 시간은 개인마다 다릅니다. 주로 이전 프로그래밍 경험, 학습 동기 부여, 학습 리소스 및 방법 및 학습 리듬의 영향을받습니다. 실질적인 학습 목표를 설정하고 실용적인 프로젝트를 통해 최선을 다하십시오.

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

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

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

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

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

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

See all articles

핫 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 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 채팅 명령 및 사용 방법
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

ZendStudio 13.5.1 맥

ZendStudio 13.5.1 맥

강력한 PHP 통합 개발 환경

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

에디트플러스 중국어 크랙 버전

에디트플러스 중국어 크랙 버전

작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

안전한 시험 브라우저

안전한 시험 브라우저

안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구