众多bot都有自己的查分功能,为啥我的不行?

我也要搞。

正好放寒假,趁成绩还没出完放松一波,把这个坑填掉。

原网址:Arcaea查分器

#01 分析源数据传输格式

先请求一次,抓一个包看看怎么嫖数据。

进行一次查分请求后获得了如下结果:

从上图可以看出,数据传输时用的协议是WebSocket协议。

查分流程大致如下所示:

继续看数据交换过程,发现查分时的查分数据({data})是用二进制流传输的。下一步就是要将这些二进制数据接码为可读的数据。

观察Request请求头,可发现Accept-Encoding: gzip, deflate, br一句,表明可能的编码方式为gzip/deflate/brotli。分开测试是不可能测试的,直接看网页缓存,就可发现brotli_decompress.min.js这一表征brotli压缩的js文件。

#02 适配Java平台

是时候展现CTRLC+CTRLV大法了。从别处抄来WebSocket的实现,又从别处抄来了Apache Commons Compress的解压例程,复制粘贴替换一气呵成。

可用的代码如下:

static WebSocketClient client;
    public static void main(String[] args) {
        try {
            client = new WebSocketClient(new URI("wss://arc.estertion.win:616/"), new Draft_6455()) {
                @Override
                public void onOpen(ServerHandshake serverHandshake) {
                    System.out.println("握手成功");
                }

                @Override
                public void onMessage(String msg) {
                    System.out.println("收到消息==========" + msg);
                    if (msg.equals("bye")) {
                        client.close();
                    }
                }

                @Override
                public void onMessage(ByteBuffer bytes) {
                    try {
                        System.out.println("收到消息字节流消息==========" + new String(BrotliUtil.deCompress(bytes.array()), StandardCharsets.UTF_8));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onClose(int i, String s, boolean b) {
                    System.out.println("链接已关闭");
                }

                @Override
                public void onError(Exception e) {
                    e.printStackTrace();
                    System.out.println("发生错误已关闭");
                }
            };
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }

        client.connect();
        while (client.getReadyState().equals(ReadyState.NOT_YET_CONNECTED)) {
            System.out.println("正在连接...");
        }
        while (!client.getReadyState().equals(ReadyState.OPEN)) {
            System.out.println("仍在连接...");
        }
        //连接成功,发送好友码
        client.send("932358780");
    }

测试一下,成功获得了查分数据。