JAVA抖音 WSS弹幕

更新websocket读取数据。

数据格式变化不大,没有太复杂的加密。

外层多包了一层proto协议,数据增加了gzip压缩。

废话不多说,下面详细介绍。

一、浏览器包依旧采用微软playwright引擎包,访问网址,监控websocket数据收发。proto相关包也必不可少。关键引用如下。

      <dependency>
            <groupId>com.microsoft.playwright</groupId>
            <artifactId>playwright</artifactId>
            <version>1.17.1</version>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.5.1</version>
        </dependency>
    <!--    <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.5.1</version>
        </dependency>-->
        <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util -->
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
            <version>3.5.1</version>
        </dependency>

二、proto数据协议,除了原有的message外,更新了对response也进行了封装。proto文件格式大致如下

syntax = "proto3";
option java_outer_classname = "WSS";//生成的外部类名,同时也是文件名
option java_package = "com.yplan.dm.proto";//生成的外部类名,同时也是文件名

message WssResponse{
  int64 wss_push_room_id = 1;
  int64 wss_push_did = 2;
  int64 wss_push_log_id = 3;
  int64 wss_fetch_ms = 4;
  int64 wss_push_ms = 5;
  string wss_msg_type = 6;
  string pb = 7;
  bytes data = 8;
  int64 server_time = 9;
  string compress_type = 10;
}

消息的proto

syntax = "proto3";
option java_outer_classname = "DanmuvoWSS";//生成的外部类名,同时也是文件名
option java_package = "com.yplan.dm.proto";//生成的外部类名,同时也是文件名

message Response{
  repeated Message messages = 1;
  string cursor = 2;
  int64 fetchInterval = 3;
  int64 now = 4;
  string internalExt = 5;
  int32 fetchType = 6;
  map<string, string> routeParams = 7;
  int64 heartbeatDuration = 8;
  bool needAck = 9;
  string pushServer = 10;
}

message Message{
  string method = 1;
  bytes payload = 2;
  int64 msgId = 3;
  int32 msgType = 4;
  int64 offset = 5;
}
……
……
……
比较长省略了,和改为websocket之前一样

关键代码如下; 【playwright 访问直播间】->【监听websocket返回值】->【数据解析】

 private void trackDouyin() {
        try (Playwright playwright = Playwright.create()) {
            Browser browser = playwright.webkit().launch();
            Page page = browser.newPage();
//                page.emulateMedia(null);
         
            Map<String, String> map = new HashMap<>();
            Consumer<Request> listener = request -> {
//                    if (request.url().startsWith("https://live.douyin.com/webcast/im/fetch/?")) {
            };
            //监听websocket
            page.onWebSocket(new Consumer<WebSocket>() {
                @Override
                public void accept(WebSocket webSocket) {
                    webSocket.onFrameReceived(new Consumer<WebSocketFrame>() {
                        @Override
                        public void accept(WebSocketFrame webSocketFrame) {
                            final byte[] data = webSocketFrame.binary();
                            System.out.println("::::::::::::::::::::::::::::::::::::::::::::::::::::::::");
                            try {
                                //最外层解析 try catch 不指定ws路径也可以,解析失败不会崩溃
                                //proto解析外层
                                WSS.WssResponse wss = WSS.WssResponse.parseFrom(data);
                                System.out.println(wss);
                                //GZIP解压data数据
                                final byte[] uncompress = Utils.uncompress(wss.getData());
                                //解析data
                                DanmuvoWSS.Response response = DanmuvoWSS.Response.parseFrom(uncompress);
                                final List<DanmuvoWSS.Message> messagesList = response.getMessagesList();
                                System.out.println(messagesList);
                                //根据message区分message类型解析 与之前接口相同
                                decodeMessage(messagesList, manager);
                            } catch (InvalidProtocolBufferException e) {
                                e.printStackTrace();
                            }

                            System.out.println("11111111111111111111111111111111111111111111111111111111111111111111111111111111");
                            System.out.println("::::::::::::::::::::::::::::::::::::::::::::::::::::::::");

                        }
                    });
                }
            });

            page.onRequestFinished(listener);
            //访问页面
            page.navigate(url);
//                browser.startTracing();

            while (true) {
                try {
                    //循环访问激活页面
                    page.content();
                    if (stop) {
                        if (manager != null) {
                            browser.close();
                            closeManager();

                        }
                        break;
                    }
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

GZIP解压采用JAVA原生即可

public static byte[] uncompress(ByteString bytes1) {
        final byte[] bytes = bytes1.toByteArray();
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        try {
            GZIPInputStream ungzip = new GZIPInputStream(in);
            byte[] buffer = new byte[5096];
            int n;
            while ((n = ungzip.read(buffer)) >= 0) {
                out.write(buffer, 0, n);
            }
        } catch (IOException e) {
            System.out.println("gzip uncompress error."+ e);
        }

        return out.toByteArray();
}

简单搭建页面-实现效果;

GZH搜“桃哥543技术交流”,获取发"弹幕"源码

 

  • 8
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 27
    评论
要在Java中实现WebSocket协议,可以使用Java API for WebSocket(JSR-356)。下面是一个简单的示例代码,演示了如何使用Java API for WebSocket来实现WebSocket服务器: ```java import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; @ServerEndpoint(value = "/myendpoint") public class MyWebSocketServer { @OnOpen public void onOpen(Session session) { System.out.println("WebSocket opened: " + session.getId()); } @OnMessage public void onMessage(String message, Session session) throws IOException { System.out.println("WebSocket message received: " + message); session.getBasicRemote().sendText("Received message: " + message); } @OnClose public void onClose(Session session) { System.out.println("WebSocket closed: " + session.getId()); } @OnError public void onError(Session session, Throwable t) { System.err.println("WebSocket error: " + t.getMessage()); } } ``` 在上面的代码中,我们使用了@ServerEndpoint注解来定义WebSocket服务器的端点,即WebSocket服务器的URL。在onOpen方法中,我们打印了一个WebSocket连接已经建立的消息。在onMessage方法中,我们打印了收到的消息,并发送了一个回复消息。在onClose方法中,我们打印了WebSocket连接已经关闭的消息。在onError方法中,我们打印了WebSocket发生错误的消息。 这只是一个简单的示例,实际上WebSocket还有很多基于事件的API和功能,例如发送二进制数据、发送Ping和Pong消息等,您可以参考Java API for WebSocket的文档来深入了解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桃哥543

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值