斗鱼连接弹幕Demo_pythonC#

简明扼要的说下, 就两个线程,一个 负责收数据,一个负责发心跳包。

步骤如下,

进程1,调用 发包函数,发送连接请求,然后再发送 获取弹幕类型请求,就一直循环接收数据。

进程2,循环函数,每隔45秒向服务器发一次心跳包。

因为斗鱼自己定义了 包头,,所以来在发包之前,先发送包数据。12个字节,

消息头部:消息长度 4字节 +消息类型4字节+加密字段2字节(默认为0)+保留字段2字节(默认为0)

然后就要把要发的内容 加上 “\0”,utf-8 编码后就能发送了

完整的 消息是:包头 + 内容 +”\0”;

上Python代码:

main.py

import socket
import time
import threading
import multiprocessing
from barrage_func import * #  导入自定义方法

SERVER_DOMAIN = "openbarrage.douyutv.com"  # 弹幕服务器 域名
SERVER_PORT = 8601;  # 弹幕服务器 端口
ROOM_ID = 288016;   #房间ID

global FIX_TAIL #拼接处理后被丢弃的数据,防止弹幕丢失
FIX_TAIL = ""
global gl_client #全局socket
gl_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

def init_socket():
    global gl_client
    host_ip = socket.gethostbyname(SERVER_DOMAIN)
    gl_client.connect((host_ip, SERVER_PORT))
def sendDate(client,data):
    data = data + ‘\0‘   #斗鱼独创序列化文本数据,结尾必须为‘\0‘
    data_length = length = len(data)+8  #斗鱼协议在尾部加了 消长度4字节,消息类型2字节(689),加密字段1字节,保留字段1字节,
    code = 689  # 消息类型
    # 消息头部:消息长度+消息类型+加密字段(默认为0)+保留字段(默认为0)
    head = data_length.to_bytes(4, ‘little‘) + data_length.to_bytes(4, ‘little‘) + code.to_bytes(2,‘little‘)+ (0).to_bytes(2,‘little‘)
    # head = int.to_bytes(data_length, 4, ‘little‘) + int.to_bytes(data_length, 4, ‘little‘) + int.to_bytes(code, 4,‘little‘)
    client.sendall(head) # 发送头部部分
    msg = (data).encode(‘utf-8‘)  # 使用utf-8编码 数据部分
    client.sendall(bytes(msg))   # 发送数据部分

def getdanmu(client):
    login = ‘type@=loginreq/roomid@=%s/‘ % ROOM_ID
    sendDate(client,login)
    joingroup = ‘type@=joingroup/rid@=%s/gid@=-9999/‘ % ROOM_ID
    sendDate(client,joingroup)
    while True:
        try:
            part_body = client.recv(1024,socket.MSG_WAITALL)
            if not part_body:   #如果 服务器发送终止连接b‘‘,则终止会话
                break
            msg_str = part_body.decode(encoding="utf-8", errors="ignore")
            get_type(msg_str)

        except Exception as e:
            print("getdanmu未知错误: %s" % e)
            continue

def get_type(msg_str):
    global FIX_TAIL
    msg_str = FIX_TAIL + msg_str
    msg_arr = msg_str.split("type@=")
    FIX_TAIL = msg_arr.pop()
    for value in msg_arr:
        type_temp = value.split("/")
        if len(type_temp) >= 2:
            type_name = type_temp[0]
            if type_name == "chatmsg":
                chatmsg =BRRAGE_FUC.get_chatmsg(value)  #获取弹幕类
                print("["+chatmsg.nn+"]: "+chatmsg.txt)
                # pass
            elif type_name == "dgb":
                dgb = BRRAGE_FUC.get_Dbg(value)  #获取礼物类
                print("感谢[{}] ,赠送的 {} 个 ‘{}‘".format(dgb.nn,int(dgb.gfcnt) * int(dgb.hits),dgb.gfid))
                # pass
            elif type_name == "uenter":
                uenter=BRRAGE_FUC.get_uenter(value)  #获取进入房间类
                print("欢迎 ["+ uenter.nn+"] " + "进入直播间")
                # pass
            elif type_name == "spbc":
                spbc = BRRAGE_FUC.get_spbc(value)  # 获取房间广播类
                print("{} 房间,[{}]赠送给[{}] {} 个 ‘{}‘".format(spbc.drid,spbc.sn,spbc.dn,spbc.gc, spbc.gn))

def keep_alive(client):
    ‘‘‘ 客户端每隔 45 秒发送心跳信息给弹幕服务器 ‘‘‘
    while True:
        alive_msg = "type@=mrkl/"  #新版本
        # alive_msg = "type@=keeplive/tick@=%s/" % int(time.time())  #旧版本
        sendDate(client,alive_msg)
        time.sleep(20)

if __name__ == ‘__main__‘:
    init_socket()
    p1 = multiprocessing.Process(target=getdanmu, args=(gl_client,))
    p2 = multiprocessing.Process(target=keep_alive, args=(gl_client,))
    p1.start()
    p2.start()

这里引用了 2个文件,

1个是定义了4个类发言弹幕Brrage_Msg(),赠送礼物Brrage_Dgb(),用户进入房间Brrage_Enter(),广播消息Brrage_Spbc ()

1 个是 写了静态方法BRRAGE_FUC 对上面的类进行 赋值

barrage_func.py

import time
from barrage_info import *
class BRRAGE_FUC(object):
    ‘‘‘  常被调用的静态方法  ‘‘‘

    #提取发言弹幕
    @staticmethod
    def get_chatmsg(msg):
        brrage_msg =Brrage_Msg()
        #获取当时时间 eg: ‘2019-02-16 18:50:02‘
        brrage_msg.time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        key_value_list =  msg.split("/")
        for key_value_temp in key_value_list:
            key_value=key_value_temp.split("@=",1)
            if len(key_value)==2:
                if key_value[0]=="rid":
                    brrage_msg.rid =str(key_value[1])
                elif key_value[0]=="uid":
                    brrage_msg.uid =str(key_value[1])
                elif key_value[0]=="nn":
                    brrage_msg.nn =str(key_value[1])
                elif key_value[0]=="txt":
                    brrage_msg.txt=str(key_value[1])
                elif key_value[0]=="cid":
                    brrage_msg.cid =str(key_value[1])
                elif key_value[0]=="nl":
                    brrage_msg.nl =str(key_value[1])
                elif key_value[0]=="level":
                    brrage_msg.level =str(key_value[1])
                elif key_value[0]=="bnn":
                    brrage_msg.bnn =str(key_value[1])
                elif key_value[0]=="bl":
                    brrage_msg.bl =str(key_value[1])
                elif key_value[0]=="brid":
                    brrage_msg.brid =str(key_value[1])
        return brrage_msg

    #提取送礼物弹幕
    @staticmethod
    def get_Dbg(msg):
        brrage_dgb = Brrage_Dgb()
        # 获取当时时间 eg: ‘2019-02-16 18:50:02‘
        brrage_dgb.time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        key_value_list = msg.split("/")
        for key_value_temp in key_value_list:
            key_value = key_value_temp.split("@=",1)
            if len(key_value) == 2:
                if key_value[0] == "rid":
                    brrage_dgb.rid = key_value[1]
                elif key_value[0] == "uid":
                    brrage_dgb.uid = key_value[1]
                elif key_value[0] == "nn":
                    brrage_dgb.nn = key_value[1]
                elif key_value[0] == "sn":
                    brrage_dgb.sn = key_value[1]
                elif key_value[0] == "gfid":
                    brrage_dgb.gfid = key_value[1]
                elif key_value[0] == "gfcnt":
                    brrage_dgb.gfcnt = key_value[1]
                elif key_value[0] == "hits":
                    brrage_dgb.hits = key_value[1]
        return brrage_dgb

    #提取用户进房通知弹幕
    @staticmethod
    def get_uenter(msg):
        brrage_enter = Brrage_Enter()
        key_value_list = msg.split("/")
        for key_value_temp in key_value_list:
            key_value = key_value_temp.split("@=",1)
            if len(key_value) == 2:
                if key_value[0] == "rid":
                    brrage_enter.rid = key_value[1]
                if key_value[0] == "uid":
                    brrage_enter.uid = key_value[1]
                if key_value[0] == "nn":
                    brrage_enter.nn = key_value[1]
                if key_value[0] == "nl":
                    brrage_enter.nl = key_value[1]
        return brrage_enter

    #飞机、火箭 广播消息
    @staticmethod
    def get_spbc(msg):
        brrage_spbc = Brrage_Spbc()
        key_value_list = msg.split("/")
        for key_value_temp in key_value_list:
            key_value = key_value_temp.split("@=",1)
            if len(key_value) == 2:
                if key_value[0] == "rid":
                    brrage_spbc.id = key_value[1]
                if key_value[0] == "drid":
                    brrage_spbc.drid = key_value[1]
                if key_value[0] == "uid":
                    brrage_spbc.uid = key_value[1]
                if key_value[0] == "sn":
                    brrage_spbc.sn = key_value[1]
                if key_value[0] == "dn":
                    brrage_spbc.dn = key_value[1]
                if key_value[0] == "gn":
                    brrage_spbc.gn = key_value[1]
                if key_value[0] == "gc":
                    brrage_spbc.gc = key_value[1]
                if key_value[0] == "gb":
                    brrage_spbc.gb = key_value[1]
                if key_value[0] == "gfid":
                    brrage_spbc.gfid = key_value[1]
        return brrage_spbc

barrage_info.py

class Brrage_Base(object):
    rid = "0"  # 房间号
    uid = "0"  # 用户id
    nn = "nn"  # 用户昵称
    time = "0000-00-00 00:00:00"  # 时间

class Brrage_Msg(Brrage_Base):
    """表示为“弹幕”消息,type固定为 chatmsg"""
    def __init__(self):
        self.txt="txt"  #弹幕文本内容
        self.cid=""   #弹幕唯一 ID
        self.nl=0   #贵族等级
        self.level =0   #用户等级
        self.bnn = ""  # 徽章昵称
        self.bl = 0  # 徽章等级
        self.brid=0   #徽章房间 id

class Brrage_Dgb(Brrage_Base):
    ‘‘‘表示为“赠送礼物”消息,type固定为 dgb ‘‘‘
    def __init__(self):

        self.gfid=0      #礼物 id
        self.gfcnt =1 #礼物个数:默认值 1
        self.hits=1   #礼物连击次数:默认值 1(表示 1 连击)

class Brrage_Enter(Brrage_Base):
    ‘‘‘ 表示为“用户进房通知”消息,type固定为 uenter ‘‘‘
    def __init__(self):
        self.nl = 0  # 贵族等级

class Brrage_Spbc(Brrage_Base):
    ‘‘‘ 房间内礼物广播,type固定为 spbc‘‘‘
    def __init__(self):
        self.drid = 0  #赠送房间 rid ,默认为0
        self.sn = ""  # 赠送者昵称
        self.dn = ""  # 受赠者昵称
        self.gn = ""  # 礼物名称
        self.gc = 1  # 礼物数量
        # self.gs = ""  # 广播样式
        self.gb = 1  # 是否有礼包(0-无礼包,1-有礼包)
        # self.es = 1  # 广播展现样式(1-火箭,2-飞机)
        self.gfid = 1  #礼物 id

运行 main.py 看效果,,比 官方弹幕 还 全,,官方应该 对 tcp 粘包没处理好。

下面的是C#的代码,原理都一样

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

namespace danmu
{
    class Program
    {
        private static string SERVER_DOMAIN = "openbarrage.douyutv.com";
        private static int SERVER_PORT = 8601;
        private static int ROOM_ID = 288016;
        private static string FIX_TAIL = String.Empty;  //拼接处理后被丢弃的数据,防止弹幕丢失
        class BrrageMsg
        {
            public string Name = String.Empty;
            public string Txt = String.Empty;
        }
        static void Main(string[] args)
        {
            try
            {
                Socket tcpClient = InitTcp(SERVER_DOMAIN, SERVER_PORT);
                Thread getDanmuThread = new Thread(GetDanmu);
                getDanmuThread.Start(tcpClient);
                Thread keepAliveThread = new Thread(KeepAlive);
                keepAliveThread.Start(tcpClient);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        static Socket InitTcp(string host, int port)
        {
            IPHostEntry hostInfo = Dns.GetHostEntry(host);
            IPAddress ipAddress = hostInfo.AddressList[0]; //域名转IP
            IPEndPoint ipe = new IPEndPoint(ipAddress, port);
            Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            s.Connect(ipe);
            return s;
        }
        static byte[] DataToBytes(string data)
        {
            string dantaNew = data + "\0";
            byte[] bodyDataByte = Encoding.UTF8.GetBytes(dantaNew);
            byte[] cType = BitConverter.GetBytes(689);

            int dataLength = dantaNew.Length + cType.Length + 8;
            byte[] dataLengthByte = BitConverter.GetBytes(dataLength);
            byte[] dataLengthByte2 = BitConverter.GetBytes(dataLength);
            byte[] result = new byte[dataLength + 4];

            Array.Copy(dataLengthByte, 0, result, 0, 4);
            Array.Copy(dataLengthByte2, 0, result, 4, 4);
            Array.Copy(cType, 0, result, 8, 4);
            Array.Copy(bodyDataByte, 0, result, 12, bodyDataByte.Length);
            byte[] source = new byte[result.Length];
            Array.Copy(result, 0, source, 0, result.Length);
            return result;
        }

        static void GetDanmu(object obj)
        {
            Socket tcpClient = (Socket)obj;
            string login = "type@=loginreq/roomid@=" + ROOM_ID + "/";
            byte[] loginBytes = DataToBytes(login);
            tcpClient.Send(loginBytes);
            string joingroup = "type@=joingroup/rid@=" + ROOM_ID + "/gid@=-9999/";
            byte[] joingroupBytes = DataToBytes(joingroup);
            tcpClient.Send(joingroupBytes);
            string recvStr = "";
            byte[] recvBytes = new byte[1024];
            int bytes;
            while (true)
            {
                bytes = tcpClient.Receive(recvBytes, recvBytes.Length, 0);//从服务器端接受返回信息
                recvStr = Encoding.UTF8.GetString(recvBytes, 0, bytes);
                ShowMsg(recvStr);
            }
        }

        static BrrageMsg GetMsgType(string[] msgType)
        {
            BrrageMsg brrageMsg = new BrrageMsg();
            foreach (string keyValueTemp in msgType)
            {
                string[] keyValue = Regex.Split(keyValueTemp, "@=", RegexOptions.IgnoreCase);
                if (keyValue.Length >= 2)
                {
                    string key = keyValue[0];
                    string[] textArr = new string[keyValue.Length - 1];
                    Array.Copy(keyValue, 1, textArr, 0, keyValue.Length - 1);
                    string value = String.Join("@", textArr);
                    if (key =="nn")
                    {
                        brrageMsg.Name = value;
                    }
                    if ((key == "txt"))
                    {
                        brrageMsg.Txt = value;
                    }
                }
            }
            return brrageMsg;
        }
        static void ShowMsg(string msg)
        {
            msg = FIX_TAIL + msg;
            string[] chatmsgArray = Regex.Split(msg, "type@=", RegexOptions.IgnoreCase);
            FIX_TAIL = chatmsgArray[chatmsgArray.Length - 1];   //截取最后的丢弃数据,放在下个包的开头,防止数据丢失
            string[] newChatmsgArrayArr = new string[chatmsgArray.Length - 1];
            Array.Copy(chatmsgArray, 0, newChatmsgArrayArr, 0, chatmsgArray.Length - 1);

            foreach (string t in newChatmsgArrayArr)
            {
                string[] msgType = t.Split(‘/‘);
                if (msgType.Length >= 2)
                {
                    string type = msgType[0];
                    if (type == "chatmsg")
                    {
                        BrrageMsg brrageMsg=GetMsgType(msgType);
                        string result = String.Format("[{0}]: {1}", brrageMsg.Name, brrageMsg.Txt);
                        Console.WriteLine(result);
                    }
                }
            }
        }
        static void KeepAlive(object obj)
        {
            Socket tcpClient = (Socket)obj;
            byte[] aliveMsg = DataToBytes("type@=mrkl/");
            while (true)
            {
                tcpClient.Send(aliveMsg);
                Thread.Sleep(40000);
            }
        }
    }
}

原文地址:https://www.cnblogs.com/likehc/p/10427130.html

时间: 2024-10-13 23:58:38

斗鱼连接弹幕Demo_pythonC#的相关文章

Python爬取斗鱼的弹幕,看看奇葩网友都说了些什么

0.前言 前几天(寒假前咯)闲着无聊,看到舍友们都在看斗鱼TV,虽然我对那些网络游戏都不是非常感兴趣,但是我突然间想到,如果我可以获取上面的弹幕内容,不就有点意思了么? 1.分析阶段 如果我想要抓取网页上面的东西,无非就是两种方法 使用浏览器,手工(自己点击)或者非手工(使用JS脚本),存取我想要的东西. 编写HTTP客户端(斗鱼无HTTPS通讯) 第一种方法是万能的,但显然是不行的, 原因如下: 学习Python中有不明白推荐加入交流裙                  号:653466668

.NET斗鱼直播弹幕客户端(上)

现在直播平台由于弹幕的存在,主播与观众可以更轻松地进行互动,非常受年轻群众的欢迎.斗鱼TV就是一款非常流行的直播平台,弹幕更是非常火爆.看到有不少主播接入弹幕语音播报器.弹幕点歌等模块,这都需要首先连接斗鱼弹幕. 经常看到其它编程语言的开发者,分享了他们斗鱼弹幕客户端的代码..NET当然也能做,还能做得更好(只是不知为何很少见人分享??). 本文将包含以下内容: 我将使用斗鱼TV官方公开的弹幕PDF文档,使用Socket/TcpClient连续斗鱼弹幕: 分析如何利用.NET强大的ValueTa

c# winfrom实时获取斗鱼房间弹幕

效果图如下: 通过webBrowser获取,时钟控件刷新弹幕,正则匹配数据,用第二个webBrowser显示弹幕内容.老话,并没完善.请自行完善.有个dll是用来屏蔽webBrowser的声音的,可能有些缺陷.得先关闭直播房间的声音然后才能起作用.具体自己测试改进.代码请点击下载:http://files.cnblogs.com/files/tuzhiyuan/%E6%96%97%E9%B1%BCTv%E5%BC%B9%E5%B9%95%E8%8E%B7%E5%8F%96%E5%8A%A9%E6

斗鱼刷弹幕js代码

对于一个网络喷子(like me)来说,喷人必须高效. var script=document.createElement("script"); script.type="text/javascript"; script.src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"; document.getElementsByTagName('head')[0].appendChild

斗鱼刷弹幕定时

(function(){ var i=0; var t=null; var msgTarea=document.getElementsByClassName("ChatSend-txt ")[0]; var btn=document.getElementsByClassName("ChatSend-button")[0]; function mySend(msg){ msgTarea.value= "主播可以加入异形系列吗?"; btn.clic

【Visual C#】基于《斗鱼弹幕服务器第三方接入协议v1.6.2》实现斗鱼弹幕服务器接入

最近在给某个主播开发斗鱼直播间辅助工具,为了程序的高效稳定,也搜索了大量的资料,经过大量什么百度,谷歌搜索... 虽然有很多Python的脚本及JS脚本实现了拉取斗鱼弹幕信息,但是这些年来的开发职业病告诉我,这满足不了对系统的控制欲望.. 后来,找啊...找啊...意外间发现这个文档....废话不多说了,说正题吧. 斗鱼很人性化的提供了一个基于Socket TCP传输协议的标准文档,通过接口我们可以安全稳定高效的获取斗鱼直播间弹幕信息,实现多种多样化的辅助功能. 一.协议组成 众所周知,受TCP

了解协议

爬虫工作流程1.请求数据协议:http https websocket注意请求过程中的 headers(请求头)中User-Agent referer cookies请求库:urllib requests 工具:fiddler charles 2.解析数据正则表达式bs4lxml-xpath 3.数据持久化文件:json txt 数据库:mysql mongodb可视化 4.反爬cookies应用ip代理验证码js加密selenium驱动chrome/phantomjs pyv8库 5.爬虫框架

【Python3爬虫】斗鱼弹幕爬虫

在网上找到了一份斗鱼弹幕服务器第三方接入协议v1.6.2,有了第三方接口,做起来就容易多了. 一.协议分析 斗鱼后台协议头设计如下: 这里的消息长度是我们发送的数据部分的长度和头部的长度之和,两个消息长度是一样.然后要注意的是该协议使用的是小端整数,所以我们要对数据进行处理后再发送,这里可以使用int.to_bytes()将整数转变成小端整数的形式.示例如下: int.to_bytes(12,4,'little')   # b'\x0c\x00\x00\x00' int.to_bytes(12,

Android弹幕功能实现,模仿斗鱼直播的弹幕效果

转载请注明出处:http://blog.csdn.net/sinyu890807/article/details/51933728 本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注,每天都有文章更新. 大家好,感觉好像已经很久没更新博客了.前段时间主要是忙于新书的事情,时间比较紧张.而现在新书已经完稿,剩下的事情就都是出版社的工作了,那么我又可以抽出时间来写写博客了. 记得之前有位朋友在我的公众号里问过我,像直播的那种弹幕功能该如何实现?如今直播行业确实是非常火爆