2025年4月9日 星期三 乙巳(蛇)年 正月初十 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > Python

Python爬虫:简易的爬取斗鱼弹幕

时间:08-24来源:作者:点击数:34

斗鱼弹幕服务器第三方接入协议v1.4.1

首先看一下协议的内容

斗鱼后台协议头设计:

请求一共分为三个部分:长度,头部,数据部

分别按照文档的要求构造就行,

需要注意的是,获取和返回的类型是都是Bytes

  • def send_request_msg(msgstr):
  • msg = msgstr.encode('utf-8') # 协议规定所有协议内容均为 UTF-8 编码
  • data_lenth = len(msg) + 8
  • # data_lenth表示整个协议头的长度(消息长度),包括数据部分和头部,len(msg)就是数据部分,8就是头部的长度
  • code = 689
  • # 根据协议消息类型字段用689
  • msghead = int.to_bytes(data_lenth, 4, 'little') + int.to_bytes(data_lenth, 4, 'little') + int.to_bytes(code, 4, 'little')
  • # msghead是按照斗鱼第三方协议构造的协议头,前2段表示的是消息长度,最后一个是消息类型
  • client.send(msghead) # 发送协议头
  • client.send(msg) # 发送消息请求

然后是获取弹幕:

也是按照文档要求写就成。首先发送登录请求,接着每隔固定时间发送心跳请求防止断线

  • def get_bulletscreen(roomid):
  • id_msg_list = []
  • denglu_msg = 'type@=loginreq/roomid@={}/\0'.format(roomid) # 登录请求消息,最后面的'\0',是协议规定在数据部分结尾必须是'\0'
  • send_request_msg(denglu_msg)
  • join_room_msg = 'type@=joingroup/rid@={}/gid@=-9999/\0'.format(roomid) # 加入房间分组消息
  • send_request_msg(join_room_msg)
  • while True:
  • data = client.recv(1024)
  • # 这个data就是服务器向客户端发送的消息
  • bulletscreen_username = re.findall(user_id, data)
  • bulletscreen_content = re.findall(bulletscreen, data)
  • # print(data)
  • if not data:
  • break
  • else:
  • for i in range(0, len(bulletscreen_username)):
  • try:
  • print('[{}]:{}'.format(bulletscreen_username[i].decode('utf-8'), bulletscreen_content[i].decode('utf-8')))
  • # 返回的数据是bytes型,所以要用decode方法来解码
  • id_msg_list.append(bulletscreen_username[i].decode('utf-8'))
  • id_msg_list.append(bulletscreen_content[i].decode('utf-8'))
  • except:
  • continue
  • # 维持与后台的心跳
  • def keeplive():
  • while True:
  • live_msg = 'type@=keeplive/tick@=' + str(int(time.time())) + '/\0'
  • send_request_msg(live_msg)
  • time.sleep(15)

完整代码

  • import re
  • import socket
  • import signal
  • import multiprocessing
  • import time
  • client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  • port = 8602 # 端口8601、8602、12601、12602这几个端口号都是
  • host = socket.gethostbyname('openbarrage.douyutv.com')
  • client.connect((host, port))
  • bulletscreen = re.compile(b'txt@=(.+?)/')
  • user_id = re.compile(b'nn@=(.+?)/')
  • def send_request_msg(msgstr):
  • msg = msgstr.encode('utf-8') # 协议规定所有协议内容均为 UTF-8 编码
  • data_lenth = len(msg) + 8
  • # data_lenth表示整个协议头的长度(消息长度),包括数据部分和头部,len(msg)就是数据部分,8就是头部的长度
  • code = 689
  • # 根据协议消息类型字段用689
  • msghead = int.to_bytes(data_lenth, 4, 'little') + int.to_bytes(data_lenth, 4, 'little') + int.to_bytes(code, 4, 'little')
  • # msghead是按照斗鱼第三方协议构造的协议头,前2段表示的是消息长度,最后一个是消息类型
  • client.send(msghead) # 发送协议头
  • client.send(msg) # 发送消息请求
  • def get_bulletscreen(roomid):
  • id_msg_list = []
  • denglu_msg = 'type@=loginreq/roomid@={}/\0'.format(roomid) # 登录请求消息,最后面的'\0',是协议规定在数据部分结尾必须是'\0'
  • send_request_msg(denglu_msg)
  • join_room_msg = 'type@=joingroup/rid@={}/gid@=-9999/\0'.format(roomid) # 加入房间分组消息
  • send_request_msg(join_room_msg)
  • while True:
  • data = client.recv(1024)
  • # 这个data就是服务器向客户端发送的消息
  • # 具体的信息可以看斗鱼弹幕第三方接入协议
  • bulletscreen_username = re.findall(user_id, data)
  • bulletscreen_content = re.findall(bulletscreen, data)
  • # print(data)
  • if not data:
  • break
  • else:
  • for i in range(0, len(bulletscreen_username)):
  • try:
  • print('[{}]:{}'.format(bulletscreen_username[i].decode('utf-8'), bulletscreen_content[i].decode('utf-8')))
  • # 返回的数据是bytes型,所以要用decode方法来解码
  • id_msg_list.append(bulletscreen_username[i].decode('utf-8'))
  • id_msg_list.append(bulletscreen_content[i].decode('utf-8'))
  • except:
  • continue
  • def keeplive():
  • # 维持与后台的心跳
  • # 关于心跳消息,协议中有详细的解释
  • while True:
  • live_msg = 'type@=keeplive/tick@=' + str(int(time.time())) + '/\0'
  • send_request_msg(live_msg)
  • time.sleep(15)
  • def logout():
  • out_msg = 'type@=logout/'
  • send_request_msg(out_msg)
  • print('已退出服务器!')
  • def signal_handler(signal, frame):
  • # 捕捉ctrl + c的信号,即signal.SIGINT
  • p1.terminate() # 结束进程
  • p2.terminate() # 结束进程
  • logout()
  • if __name__ == '__main__':
  • roomid = 9999 # 房间号,主播开播才能获取到信息
  • signal.signal(signal.SIGINT, signal_handler)
  • p1 = multiprocessing.Process(target=get_bulletscreen, args=(roomid,))
  • p2 = multiprocessing.Process(target=keeplive)
  • p1.start()
  • p2.start()

运行结果

有些用户名没有获取到是因为网页版搞得什么角色弹幕,是一个图片

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门