斗鱼直播间弹幕爬取2020年最新python

PyMySQL==0.9.3
websocket_client==0.57.0

斗鱼直播间弹幕2020年最新

    我最近在学习python的直播间弹幕爬取,但是由于斗鱼官方把第三方api的接口改变了,必须要注册为开发者才能使用官方提供的方法进行弹幕爬取。所以我通过搜索教程了解到可以使用浏览器自带的爬取功能对弹幕进行爬取。

原理如下:

利用websocket建立wss 连接

wss://danmuproxy.douyu.com:8506/'

8501-8507都可以使用。

发送登录信息

发生入组信息

发送心跳数据,(和b站不一样更高级了,有心跳数据了)。

利用wss必须对发送包进行加密,对接收的数据进行解包,

这些操作官方api 有提供,所以我就不再进行解释了。

就能返回弹幕数据。完整代码如下,将roomid = "666743" 改成你需要的id。

以下代码并非我独创,有借鉴别人的。

import websocket
import threading
import time
class DyDanmuMsgHandler:
    # 将字符串数据按照斗鱼协议封装为字节流
    def dy_encode(self,msg):
        # 头部8字节,尾部1字节,与字符串长度相加即数据长度
        # 为什么不加最开头的那个消息长度所占4字节呢?这得问问斗鱼^^
        data_len = len(msg) + 9
        # 字符串转化为字节流
        msg_byte = msg.encode('utf-8')
        # 将数据长度转化为小端整数字节流
        len_byte = int.to_bytes(data_len, 4, 'little')
        # 前两个字节按照小端顺序拼接为0x02b1,转化为十进制即689(《协议》中规定的客户端发送消息类型)
        # 后两个字节即《协议》中规定的加密字段与保留字段,置0
        send_byte = bytearray([0xb1, 0x02, 0x00, 0x00])
        # 尾部以'\0'结束
        end_byte = bytearray([0x00])
        # 按顺序拼接在一起
        data = len_byte + len_byte + send_byte + msg_byte + end_byte
        return data

    def __parse_msg(self,raw_msg):
        '''
        解析数据
        :param raw_msg: 原始response数据
        :return:
        '''
        res = {}
        attrs = raw_msg.split('/')[0:-1]
        for attr in attrs:
            attr = attr.replace('@s','/')
            attr = attr.replace('@A','@')
            couple = attr.split('@=')
            res[couple[0]] = couple[1]
        return res

    def dy_decode(self,msg_byte):
        '''
        解析斗鱼返回的数据
        :param msg_byte:
        :return:
        '''
        pos = 0
        msg = []
        while pos < len(msg_byte):
            content_length = int.from_bytes(msg_byte[pos: pos + 4], byteorder='little')
            content = msg_byte[pos + 12: pos + 3 + content_length].decode(encoding='utf-8', errors='ignore')
            msg.append(content)
            pos += (4 + content_length)
        return msg
    
    def get_chat_messages(self,msg_byte):
        '''
        从数据获取chatmsg数据
        :param msg_byte:
        :return:
        '''
        decode_msg = self.dy_decode(msg_byte)
        messages = []
        for msg in decode_msg:
            res = self.__parse_msg(msg)
            if res['type'] !='chatmsg':
                continue
            messages.append(res)
        return messages    

class DyDanmuCrawler:
    def __init__(self,roomid):
        self.__room_id = roomid
        self.__heartbeat_thread = None
        self.__client = DyDanmuWebSocketClient(on_open=self.__prepare,
                                               on_message=self.__receive_msg,
                                               on_close=self.__stop)
        self.__msg_handler =  DyDanmuMsgHandler()
        self.__keep_HeartBeat = True
    
    def start(self):
        '''
        开启客户端
        :return:
        '''
        self.__client.start()

    def __stop(self):
        '''
        登出
        停止客户端
        停止心跳线程
        :return:
        '''
        self.__logout()
        self.__client.stop()
        self.__keep_HeartBeat=False


    def on_error(self, error):
        print(error)

    def on_close(self):
        print('close')

    # 发送入组消息
    def join_group(self):
        '''
        发送群组消息
        :return:
        '''
        join_group_msg = 'type@=joingroup/rid@=%s/gid@=1/' % (self.__room_id)
        msg_bytes = self.__msg_handler.dy_encode(join_group_msg)
        self.__client.send(msg_bytes)

    # 发送登录请求消息
    def login(self):
        '''
        登陆
        :return:
        '''
        login_msg = 'type@=loginreq/roomid@=%s/dfl@=sn@AA=105@ASss@AA=1/' \
                    'username@=%s/uid@=%s/ver@=20190610/aver@=218101901/ct@=0/.'%(
            self.__room_id,'99047358','99047358'
        )
        msg_bytes = self.__msg_handler.dy_encode(login_msg)
        self.__client.send(msg_bytes)

    def __start_heartbeat(self):
        self.__heartbeat_thread = threading.Thread(target=self.__heartbeat)
        self.__heartbeat_thread.start()

    def __heartbeat(self):
        heartbeat_msg = 'type@=mrkl/'
        heartbeat_msg_byte = self.__msg_handler.dy_encode(heartbeat_msg)
        while True:
            self.__client.send(heartbeat_msg_byte)
            for i in range(90):
                time.sleep(0.5)
                if  not self.__keep_HeartBeat:
                    return

    def __prepare(self):
        self.login()
        # 登录后发送入组消息
        self.join_group()
        self.__start_heartbeat()


    def __receive_msg(self, msg):
        '''
        处理收到的信息
        :param msg:
        :return:
        '''
        chat_messages =self.__msg_handler.get_chat_messages(msg)
        for message in chat_messages:
            print(f"{message['nn']}:{message['txt']}")
        # 将字节流转化为字符串,忽略无法解码的错误(即斗鱼协议中的头部尾部)
        #print(message.decode(encoding='utf-8', errors='ignore'))

class DyDanmuWebSocketClient:
    def __init__(self,on_open,on_message,on_close):
        self.__url ='wss://danmuproxy.douyu.com:8506/'
        self.__websocket =  websocket.WebSocketApp(self.__url,
                                                   on_open=on_open,
                                                   on_message=on_message,
                                                   on_error=self.__on_error,
                                                   on_close=on_close)

    def start(self):
        self.__websocket.run_forever()

    def stop(self):
        self.__websocket.close()

    def send(self,msg):
        self.__websocket.send(msg)

    def __on_error(self,error):
        print(error)


roomid = "666743"
dy_barrage_crawler = DyDanmuCrawler(roomid)
dy_barrage_crawler.start()

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值