更新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技术交流”,获取发"弹幕"源码