1.斗鱼弹幕协议

到斗鱼官方开放平台看斗鱼通讯协议,网址“https://open.douyu.com/source/api/63”,登录后可查看

所以根据斗鱼协议做编码函数:def msg_encode(msg):

#消息以 \0 结尾,并以utf-8编码

msg = msg + '\0'

msg_bytes = msg.encode('utf-8')

#消息长度 + 头部长度8

length_bytes = int.to_bytes(len(msg) + 8, 4, byteorder='little')

#斗鱼客户端发送消息类型 689

type = 689

type_bytes = int.to_bytes(type, 2, byteorder='little')

# 加密字段与保留字段,默认 0 长度各 1

end_bytes = int.to_bytes(0, 1, byteorder='little')

#按顺序相加 消息长度 + 消息长度 + 消息类型 + 加密字段 + 保留字段

head_bytes = length_bytes + length_bytes + type_bytes + end_bytes + end_bytes

#消息头部拼接消息内容

data = head_bytes + msg_bytes

return data

然后根据斗鱼协议做解码函数:def msg_decode(msg_bytes):

#定义一个游标位置

cursor = 0

msg = []

while cursor < len(msg_bytes):

#根据斗鱼协议,报文 前四位与第二个四位,都是消息长度,取前四位,转化成整型

content_length = int.from_bytes(msg_bytes[cursor: (cursor + 4) - 1], byteorder='little')

#报文长度不包含前4位,从第5位开始截取消息长度的字节流,并扣除前8位的协议头,取出正文,用utf-8编码成字符串

content = msg_bytes[(cursor + 4) + 8:(cursor + 4) + content_length - 1].decode(encoding='utf-8',

errors='ignore')

msg.append(content)

cursor = (cursor + 4) + content_length

# print(msg)

return msg

解码后的消息需要反序列化:def msg_format(msg_str):

try:

msg_dict = {}

msg_list = msg_str.split('/')[0:-1]

for msg in msg_list:

msg = msg.replace('@s', '/').replace('@A', '@')

msg_tmp = msg.split('@=')

msg_dict[msg_tmp[0]] = msg_tmp[1]

return msg_dict

except Exception as e:

print(str(e))

2.抓包分析

建议通过chrome开发者工具抓包,或者使用fiddler抓包,网页的东西,直接用chrome更方便

为什么不用斗鱼开放平台提供的api直接用呢,因为api是面向注册的开发者的,api都需要申请使用,普通用户只能抓包分析通用接口

分析:

wsproxy.douyu.com中交互消息可以获得多个弹幕服务器地址,我们直接取一个就行,不需要在程序中实现实时分析

然后分析danmuproxy.douyu.com连接中详细交互信息,实现与服务器交互

匿名登录时弹幕中礼物消息可能默认被屏蔽,需在登录时提交开启指令,或登录后提交开启指令

弹幕消息类型与指令非常丰富,这里举例简单的消息和指令,详细可以继续分析

结果如下:

登录:type@=loginreq/roomid@=74751/dfl@=/username@=visitor8243989/uid@=1132317461/ver@=20190610/aver@=218101901/ct@=0/

##匿名分配的username与uid可以从wsproxy.douyu.com中交互消息获取,也可直接自定义提交就行

退出登录:type@=logout/

心跳消息:type@=mrkl/

加入组消息:type@=joingroup/rid@=74751/gid@=-9999/ #gid默认1,此处改成 - 9999 改成海量弹幕模式

屏蔽礼物消息:type@=dmfbdreq/dfl@=sn@AA=105@ASss@AA=1@AS@Ssn@AA=106@ASss@AA=1@AS@Ssn@AA=107@ASss@AA=1@AS@Ssn@AA=108@ASss@AA=1@AS@Ssn@AA=110@ASss@AA=1@AS@Ssn@AA=901@ASss@AA=1@AS@S/

开启礼物消息:type@=dmfbdreq/dfl@=sn@AA=105@ASss@AA=0@AS@Ssn@AA=106@ASss@AA=0@AS@Ssn@AA=107@ASss@AA=0@AS@Ssn@AA=108@ASss@AA=0@AS@Ssn@AA=110@ASss@AA=0@AS@Ssn@AA=901@ASss@AA=0@AS@S/

##开启与屏蔽礼物可以详细控制,可以逐项尝试分析

注:登录消息中有个字段/dfl@=,此处直接加入屏蔽礼物或开启礼物指令中相应dfl@=后面的内容,即可在登录时控制礼物屏蔽或开启

3.礼物消息处理

获取斗鱼礼物类型,需抓包分析来源网址

url1 = 'https://webconf.douyucdn.cn/resource/common/gift/flash/gift_effect.json'

url2 = 'https://webconf.douyucdn.cn/resource/common/prop_gift_list/prop_gift_config.json'

将获取到的礼物json处理一下,合并且去除不需要信息,做成字典:

def get_gift_dict():

gift_json = {}

gift_json1 = requests.get('https://webconf.douyucdn.cn/resource/common/gift/flash/gift_effect.json').text

gift_json2 = requests.get('https://webconf.douyucdn.cn/resource/common/prop_gift_list/prop_gift_config.json').text

gift_json1=gift_json1.replace('DYConfigCallback(','')[0:-2]

gift_json2=gift_json2.replace('DYConfigCallback(','')[0:-2]

gift_json1 = json.loads(gift_json1)['data']['flashConfig']

gift_json2= json.loads(gift_json2)['data']

for gift in gift_json1:

gift_json[gift] = gift_json1[gift]['name']

for gift in gift_json2:

gift_json[gift] = gift_json2[gift]['name']

return gift_json

4.websocket连接

python环境先安装websocket包 pip3 install websocket-client

引入websocket包后,使用websecket.WebSocketApp建立websecket连接客户端,创建时在on_open、on_error、on_message、on_close4个参数中传入相应事件发生时需要处理的方法

顾名思义,4个参数很好理解了

websocket.WebSocketApp(url, on_open=on_open, on_error=on_error,on_message=on_message, on_close=on_close)

5.效果与源码

实际效果展示:

源码(演示代码,异常判断,数据校验就不做了):

__author__ = 'admin'

import websocket

import threading

import time

import requests

import json

class DyDanmu:

def __init__(self, roomid, url):

self.gift_dict = self.get_gift_dict()

self.gift_dict_keys = self.gift_dict.keys()

self.room_id = roomid

self.client = websocket.WebSocketApp(url, on_open=self.on_open, on_error=self.on_error,

on_message=self.on_message, on_close=self.on_close)

self.heartbeat_thread = threading.Thread(target=self.heartbeat)

def start(self):

self.client.run_forever()

def stop(self):

self.logout()

self.client.close()

def on_open(self):

self.login()

self.join_group()

self.heartbeat_thread.setDaemon(True)

self.heartbeat_thread.start()

def on_error(self, error):

print(error)

def on_close(self):

print('close')

def send_msg(self, msg):

msg_bytes = self.msg_encode(msg)

self.client.send(msg_bytes)

def on_message(self, msg):

message = self.msg_decode(msg)

# print(message)

for msg_str in message:

msg_dict = self.msg_format(msg_str)

if msg_dict['type'] == 'chatmsg':

print(msg_dict['nn'] + ':' + msg_dict['txt'])

if msg_dict['type'] == 'dgb':

if msg_dict['gfid'] in self.gift_dict_keys:

print(msg_dict['nn'] + '\t送出\t' + msg_dict['gfcnt'] + '\t个\t' + self.gift_dict[msg_dict['gfid']])

else:

print(msg_dict['nn'] + '\t送出\t' + msg_dict['gfcnt'] + '\t个\t' + msg_dict['gfid'] + '\t未知礼物')

# print(msg_dict)

# 发送登录信息

def login(self):

login_msg = 'type@=loginreq/roomid@=%s/' \

'dfl@=sn@AA=105@ASss@AA=0@AS@Ssn@AA=106@ASss@AA=0@AS@Ssn@AA=107@ASss@AA=0@AS@Ssn@AA=108@ASss@AA=0@AS@Ssn@AA=110@ASss@AA=0@AS@Ssn@AA=901@ASss@AA=0/' \

'username@=%s/uid@=%s/ltkid@=/biz@=/stk@=/devid@=8d8c22ce6093e6a7264f99da00021501/ct@=0/pt@=2/cvr@=0/tvr@=7/apd@=/rt@=1605498503/vk@=0afb8a90c2cb545e8459d60c760dc08b/' \

'ver@=20190610/aver@=218101901/dmbt@=chrome/dmbv@=78/' % (

self.room_id, 'visitor4444086', '1178849206'

)

self.send_msg(login_msg)

def logout(self):

logout_msg = 'type@=logout/'

self.send_msg(logout_msg)

# 发送入组消息

def join_group(self):

join_group_msg = 'type@=joingroup/rid@=%s/gid@=-9999/' % (self.room_id)

self.send_msg(join_group_msg)

# 关闭礼物信息推送

def close_gift(self):

close_gift_msg = 'type@=dmfbdreq/dfl@=sn@AA=105@ASss@AA=1@AS@Ssn@AA=106@ASss@AA=1@AS@Ssn@AA=107@ASss@AA=1@AS@Ssn@AA=108@ASss@AA=1@AS@Ssn@AA=110@ASss@AA=1@AS@Ssn@AA=901@ASss@AA=1@AS@S/'

self.send_msg(close_gift_msg)

# 保持心跳线程

def heartbeat(self):

while True:

# 45秒发送一个心跳包

self.send_msg('type@=mrkl/')

print('发送心跳')

time.sleep(45)

def msg_encode(self, msg):

# 消息以 \0 结尾,并以utf-8编码

msg = msg + '\0'

msg_bytes = msg.encode('utf-8')

#消息长度 + 头部长度8

length_bytes = int.to_bytes(len(msg) + 8, 4, byteorder='little')

#斗鱼客户端发送消息类型 689

type = 689

type_bytes = int.to_bytes(type, 2, byteorder='little')

# 加密字段与保留字段,默认 0 长度各 1

end_bytes = int.to_bytes(0, 1, byteorder='little')

#按顺序相加 消息长度 + 消息长度 + 消息类型 + 加密字段 + 保留字段

head_bytes = length_bytes + length_bytes + type_bytes + end_bytes + end_bytes

#消息头部拼接消息内容

data = head_bytes + msg_bytes

return data

def msg_decode(self, msg_bytes):

# 定义一个游标位置

cursor = 0

msg = []

while cursor < len(msg_bytes):

#根据斗鱼协议,报文 前四位与第二个四位,都是消息长度,取前四位,转化成整型

content_length = int.from_bytes(msg_bytes[cursor: (cursor + 4) - 1], byteorder='little')

#报文长度不包含前4位,从第5位开始截取消息长度的字节流,并扣除前8位的协议头,取出正文,用utf-8编码成字符串

content = msg_bytes[(cursor + 4) + 8:(cursor + 4) + content_length - 1].decode(encoding='utf-8',

errors='ignore')

msg.append(content)

cursor = (cursor + 4) + content_length

# print(msg)

return msg

def msg_format(self, msg_str):

try:

msg_dict = {}

msg_list = msg_str.split('/')[0:-1]

for msg in msg_list:

msg = msg.replace('@s', '/').replace('@A', '@')

msg_tmp = msg.split('@=')

msg_dict[msg_tmp[0]] = msg_tmp[1]

return msg_dict

except Exception as e:

print(str(e))

def get_gift_dict(self):

gift_json = {}

gift_json1 = requests.get('https://webconf.douyucdn.cn/resource/common/gift/flash/gift_effect.json').text

gift_json2 = requests.get(

'https://webconf.douyucdn.cn/resource/common/prop_gift_list/prop_gift_config.json').text

gift_json1 = gift_json1.replace('DYConfigCallback(', '')[0:-2]

gift_json2 = gift_json2.replace('DYConfigCallback(', '')[0:-2]

gift_json1 = json.loads(gift_json1)['data']['flashConfig']

gift_json2 = json.loads(gift_json2)['data']

for gift in gift_json1:

gift_json[gift] = gift_json1[gift]['name']

for gift in gift_json2:

gift_json[gift] = gift_json2[gift]['name']

return gift_json

if __name__ == '__main__':

roomid = '74751'

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

dy = DyDanmu(roomid, url)

dy.start()

python websocket爬虫_python根据websocket抓取斗鱼弹幕和礼物消息相关推荐

  1. 通过websocket抓取斗鱼弹幕和礼物消息

    1.斗鱼弹幕协议 到斗鱼官方开放平台看斗鱼通讯协议,网址"斗鱼开放平台",登录后可查看 所以根据斗鱼协议做编码函数: 1 def msg_encode(msg):2 #消息以 \0 ...

  2. Python开发爬虫之动态网页抓取篇:爬取博客评论数据——通过浏览器审查元素解析真实网页地址...

    由于主流网站都使用JavaScript展示网页内容,和前面简单抓取静态网页不同的是,在使用JavaScript时,很多内容并不会出现在HTML源代码中,而是在HTML源码位置放上一段JavaScrip ...

  3. python爬虫----简单的抓取斗鱼弹幕

    近几年来直播越来越火,看直播也成为了人们生活的娱乐项目 个人也是比较喜欢看直播,看着主播的搞笑的操作和弹幕不时会开怀大笑. 于是就想能不能把弹幕抓取下来,带着这个问题我就点开了一个直播间.按照以前学过 ...

  4. Python新手爬虫,简单制作抓取廖雪峰教程的小爬虫

    先看几张对比图,分别是官网截图和抓取下来的 txt文档的截图,不算那难看的排版的话,内容是一致的,图片用 url替换了! 在整个抓取过程中,除了普通的文本以外,还需要处理 3个地方,分别是:代码.图片 ...

  5. Python开源爬虫项目代码:抓取淘宝、京东、QQ、知网数据--转

    数据来源:数据挖掘入门与实战  公众号: datadw scrapy_jingdong[9]- 京东爬虫.基于scrapy的京东网站爬虫,保存格式为csv.[9]: https://github.co ...

  6. Python异步爬虫之协程抓取妹子图片(aiohttp、aiofiles)

    目录 前言 一.什么是协程? 二.协程的优势 三.代码分析 1.引入库 2.获取所有时间线的链接 3.获取一个时间线中所有相册的链接 4.获取一个相册中所有的图片链接以及相册的名字 5.下载并保存图片 ...

  7. python 小说爬虫_Python实现的爬取小说爬虫功能示例

    本文实例讲述了Python实现的爬取小说爬虫功能.分享给大家供大家参考,具体如下: 想把顶点小说网上的一篇持续更新的小说下下来,就写了一个简单的爬虫,可以爬取爬取各个章节的内容,保存到txt文档中,支 ...

  8. python 广告拦截_Python如何在抓取时欺骗反广告块过滤器?

    Javascript解析 您遇到的问题是在页面加载后加载数据的JavaScript过滤器.警告您正在使用adblock的消息以原始HTML格式存在,并且是完全静态的.当JavaScript调用能够验证 ...

  9. python采集直播间数据_Python使用Selenium模块模拟浏览器抓取斗鱼直播间信息示例...

    本文实例讲述了Python使用Selenium模块模拟浏览器抓取斗鱼直播间信息.分享给大家供大家参考,具体如下: import time from multiprocessing import Poo ...

  10. python 模拟浏览器selenium_Python使用Selenium模块模拟浏览器抓取斗鱼直播间信息示例...

    本文实例讲述了Python使用Selenium模块模拟浏览器抓取斗鱼直播间信息.分享给大家供大家参考,具体如下: import time from multiprocessing import Poo ...

最新文章

  1. 生成对抗网络(Generative Adversarial Network,GAN)
  2. Ogre貌似开始推荐MYGUI了~~
  3. python现在第几版-2020 年10月编程语言排行榜,Python 排名逼近第二
  4. Java数据结构和算法:线性表
  5. 只考计算机知识吗,计算机二级只考一门吗?计算机二级考什么?
  6. Myeclipse编译工程用Weblogic发布的时候jdk版本问题
  7. ElasticSearch 全文检索— ElasticSearch 基本操作
  8. AppLinks使用详解
  9. EasyUI 1.5.1 美化主题大包 Insdep Theme 1.0.3 正式版已发布,开源下载
  10. iconfont 图标不显示
  11. python你好代码-再见,Python。你好,Go语言。
  12. 中职计算机基础辅导书,中职计算机基础 (938)(16页)-原创力文档
  13. python五种标准数据类型_python标准数据类型--数值
  14. hostent实例详解
  15. 胡塞尔与海德格尔与维特根斯坦
  16. 删库了,除了跑路还能怎么办?在线等!
  17. 商品表(spu)、规格表(sku)设计
  18. 计算机知识宣传黑板报,计算机黑板报内容
  19. 安全底层开发工程师需要学习哪些内容
  20. 中文 NLP (2) -- ICTCLAS分词

热门文章

  1. 【数据分析师-数据分析项目案例一】600w+条短租房数据案例分析
  2. 飘云阁15周年逆向破解教程
  3. 惠普1020打印机驱动安装教程
  4. 一些值得学习的Unity教程
  5. JavaWeb播放视频实现断点续传、分片上传
  6. 微博爬虫思路:Python通过移动端接口爬取,简单易操作
  7. 光纤色散是什么?如何色散补偿?
  8. PHP 缓存 内存,PHP memcache 内存缓存 数据库查询 应用 高洛峰 细说PHP
  9. 21天学通C语言-学习笔记(2)
  10. MATLAB函数取整