调用斗鱼API爬取直播间弹幕信息(用户昵称及弹幕内容)


调用斗鱼API爬取直播间弹幕信息(用户昵称及弹幕内容)

  1. 查看《斗鱼弹幕服务器第三方接入协议v1.4.1》,了解斗鱼API的使用方法,即如何连接斗鱼弹幕服务器、维持连接及获取弹幕信息
  2. Python调用斗鱼API爬取直播间弹幕信息代码和注释
  3. 爬取结果示例

1. 查看《斗鱼弹幕服务器第三方接入协议v1.4.1》,了解斗鱼API的使用方法,即如何连接斗鱼弹幕服务器、维持连接及获取弹幕信息

1.1 登陆授权

欲从后台获取弹幕信息的客户端在于服务器建立TCP连接后,需发起登陆请求(包括相关验证信息),后台验证请求信息无误后,返回登陆成功相应。

1.2 房间分组

为管理斗鱼的直播间及弹幕,后台服务器有两个重要概念:房间号分组号
房间号与主播的直播间地址为一一对应关系。一般直播间房间号可在其 URL地址中找到,例如 http://www.douyutv.com/301712其中301712即为房间号。
分组号为某特定直播间不同观众所在弹幕交流群体的标识。其意义主要为将人数过多弹幕信息量过大的直播间观众进行切割分片管理,以防止观众接收过多弹幕而导致机器负载过重。分组号为整数,一般从 0 开始动态增加改变。特别注意-9999 特殊分组号,该组成员将接受对应直播间全部弹幕,即“海量弹幕”分组。
登陆授权为获取弹幕的基础,而加入房间及其分组为获取指定直播间弹幕的必要条件。

1.3 弹幕信息

弹幕信息包括以下类型:

  • 文字弹幕
  • 领取在线鱼丸暴击消息
  • 赠送礼物消息
  • 用户进房通知消息(为感谢大力支持斗鱼平台的用户而设置的进房提示信息)
  • 用户赠送酬勤通知消息
  • 用户信息
  • 房间开关播提醒
  • 广播排行榜消息
  • 超级弹幕消息
  • 房间内礼物广播
  • 房间用户抢红包
  • 房间内 top10 变化消息

1.4 心跳信息

斗鱼的弹幕协议是建立在TCP长连接服务上的,为管理这些长连接,保证及时销毁无用的连接以释放资源服务于有需的用户,斗鱼后台需要与客户端保持心跳。(目前后台设置每45秒向后台发送一条心跳信息)

1.5 斗鱼后台协议头设计

客户端向斗鱼弹幕服务器发起请求时,发送的信息必须包括如下设计的协议头。

斗鱼后台协议头

字段说明:

  • 消息长度:4 字节小端整数,表示整条消息(包括自身)长度(字节数)。消息长度出现两遍,二者相同。
  • 消息类型:2 字节小端整数,表示消息类型。取值如下:
    689 客户端发送给弹幕服务器的文本格式数据
    (我们客户端向服务器发送的协议头要包括689)
    690 弹幕服务器发送给客户端的文本格式数据。
  • 加密字段:暂时未用,默认为 0。
  • 保留字段:暂时未用,默认为 0。(消息类型,加密字段,保留字段三个字段加在一起4字节)
  • 数据部分:斗鱼独创序列化文本数据,结尾必须为'\0'。(即发送的请求信息最后一个字符必须为'\0')

1.6 序列化

详情见文档

2. Python调用斗鱼API爬取直播间弹幕信息代码和注释

第三方客户端通过 TCP 协议连接到弹幕服务器(依据指定的 IP 和端口);
第三方接入弹幕服务器列表:
IP 地址:openbarrage.douyutv.com 端口:8601

发送请求的数据部分格式:

  1. 客户端心跳消息:
    心跳信息
  2. 登陆请求消息:
    登录请求信息
  3. 入组消息


    入组消息

获取收到的数据中的文字弹幕信息,文字弹幕信息的格式:

文字弹幕信息格式

参考资料:

'''
文件名:爬取斗鱼直播间信息到jsonline文件.py
参考的github:https://github.com/rieuse
'''
from __future__ import unicode_literals
import multiprocessing
import socket
import time
import re
import requests
from bs4 import BeautifulSoup
import json

# 配置socket的ip和端口
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostbyname("openbarrage.douyutv.com")
port = 8601
client.connect((host, port))

# 获取用户昵称及弹幕信息的正则表达式
danmu = re.compile(b'type@=chatmsg.*?/nn@=(.*?)/txt@=(.*?)/')


def sendmsg(msgstr):
    '''
    客户端向服务器发送请求的函数,集成发送协议头的功能
    msgHead: 发送数据前的协议头,消息长度的两倍,及消息类型、加密字段和保密字段
    使用while循环发送具体数据,保证将数据都发送出去
    '''
    msg = msgstr.encode('utf-8')
    data_length = len(msg) + 8
    code = 689
    msgHead = int.to_bytes(data_length, 4, 'little') \
              + int.to_bytes(data_length, 4, 'little') + int.to_bytes(code, 4, 'little')
    client.send(msgHead)
    sent = 0
    while sent < len(msg):
        tn = client.send(msg[sent:])
        sent = sent + tn


def start(roomid):
    '''
    发送登录验证请求后,获取服务器返回的弹幕信息,同时提取昵称及弹幕内容
    登陆请求消息及入组消息末尾要加入\0
    '''
    msg = 'type@=loginreq/roomid@={}/\0'.format(roomid)
    sendmsg(msg)
    msg_more = 'type@=joingroup/rid@={}/gid@=-9999/\0'.format(roomid)
    sendmsg(msg_more)

    print('---------------欢迎连接到{}的直播间---------------'.format(get_name(roomid)))
    while True:
        data = client.recv(1024)
        danmu_more = danmu.findall(data)
        if not data:
            break
        else:
            with open('bullet_curtain.jl', 'a') as f:
                try:
                    for i in danmu_more:
                        dmDict={}
                        dmDict['昵称'] = i[0].decode(encoding='utf-8', errors='ignore')
                        dmDict['弹幕内容'] = i[1].decode(encoding='utf-8', errors='ignore')
                        dmJsonStr = json.dumps(dmDict, ensure_ascii=False)+'\n'
                        print(dmDict['昵称'])
                        f.write(dmJsonStr)
                        danmuNum = danmuNum + 1
                except:
                    continue

def keeplive():
    '''
    发送心跳信息,维持TCP长连接
    心跳消息末尾加入\0
    '''
    while True:
        msg = 'type@=keeplive/tick@=' + str(int(time.time())) + '/\0'
        sendmsg(msg)
        time.sleep(10)


def get_name(roomid):
    '''
    利用BeautifulSoup获取直播间标题
    '''
    r = requests.get("http://www.douyu.com/" + roomid)
    soup = BeautifulSoup(r.text, 'lxml')
    return soup.find('a', {'class', 'zb-name'}).string

# 启动程序
if __name__ == '__main__':
    room_id = input('请输入房间ID: ')
    p1 = multiprocessing.Process(target=start, args=(room_id,))
    p2 = multiprocessing.Process(target=keeplive)
    p1.start()
    p2.start()

3. 爬取结果示例

爬取结果示例
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容