You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用PHP从无人机竞速追踪软件的WebSocket中获取赛事编号(28/28)?

使用PHP获取无人机竞速网站的编号数据是可行的!

你遇到的核心问题是:目标数据不是静态HTML内容,而是通过Socket.IO(基于WebSocket的封装协议)动态推送的,所以静态网页抓取工具(比如你用的ultimate-web-scraper)根本拿不到数据;而你尝试的curl代码,因为Socket.IO的握手流程、事件订阅逻辑不对,也没能成功建立有效连接。

问题分析

  1. 静态抓取无效:你用web scraper抓取的是页面初始HTML,但(28/28)这类实时计分数据是页面加载后通过Socket.IO从服务器推送过来的,初始HTML里没有这些内容。
  2. Socket.IO连接流程错误:你的curl代码错误地使用了页面URL作为Socket服务器地址,而实际的Socket.IO端点是wss://aircrasher.livefpv.com/socket.io/;另外你发送的事件(比如chat message)和网站实际需要的订阅事件不匹配,服务器不会推送计分数据给你。

解决方案:用PHP正确处理Socket.IO连接

要拿到数据,你需要完成Socket.IO的完整握手流程,订阅正确的事件,再监听服务器推送的消息。下面是具体实现步骤和代码示例:

1. 准备依赖

首先安装PHP的WebSocket客户端库(用于处理Socket.IO的WebSocket传输):

composer require ratchet/pawl

2. 完整代码实现

<?php
require __DIR__ . '/vendor/autoload.php';

use Ratchet\Client\WebSocket;
use React\EventLoop\Factory;

// 创建事件循环(Socket.IO需要异步处理)
$loop = Factory::create();

// 第一步:Socket.IO握手,获取会话ID(sid)
$handshakeUrl = 'https://aircrasher.livefpv.com/socket.io/?EIO=4&transport=polling';
$ch = curl_init($handshakeUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$handshakeResponse = curl_exec($ch);
curl_close($ch);

// 解析握手响应(格式:0{"sid":"xxx", ...})
$handshakeData = json_decode(substr($handshakeResponse, 1), true);
if (!$handshakeData || !isset($handshakeData['sid'])) {
    die('握手失败:无法获取Socket.IO会话ID');
}
$sid = $handshakeData['sid'];

// 第二步:建立WebSocket连接
$wsUrl = "wss://aircrasher.livefpv.com/socket.io/?EIO=4&transport=websocket&sid={$sid}";

$loop->addTimer(0.1, function () use ($loop, $wsUrl, $handshakeData) {
    WebSocket\connect($wsUrl)->then(function (WebSocket $conn) use ($loop, $handshakeData) {
        // 发送Socket.IO连接包(v4版本用"40"表示CONNECT)
        $conn->send('40');
        
        // 发送订阅计分事件(事件名需要对照网站实际流量调整,可通过浏览器开发者工具查看)
        // 这里假设网站需要订阅"joinScoring"事件,传递房间参数
        $conn->send('42["joinScoring", {"room": "live-scoring"}]');
        
        // 设置Ping定时器,保持连接(避免服务器断开)
        $pingTimer = $loop->addPeriodicTimer(($handshakeData['pingInterval'] / 1000) - 1, function () use ($conn) {
            $conn->send('2'); // Socket.IO的Ping包
        });
        
        // 监听服务器推送的消息
        $conn->on('message', function ($msg) use ($conn, $loop, $pingTimer) {
            // Socket.IO消息格式示例:42["scoringUpdate", {"current":28, "total":28, ...}]
            if (str_starts_with($msg, '42')) {
                $eventData = json_decode(substr($msg, 2), true);
                if ($eventData[0] === 'scoringUpdate') { // 确认是计分更新事件
                    $scoringInfo = $eventData[1];
                    $targetNumber = "{$scoringInfo['current']}/{$scoringInfo['total']}";
                    echo "获取到目标编号:{$targetNumber}\n";
                    
                    // 拿到数据后关闭连接、停止循环
                    $conn->close();
                    $loop->cancelTimer($pingTimer);
                    $loop->stop();
                }
            }
        });
        
        // 处理连接关闭
        $conn->on('close', function ($code = null, $reason = null) use ($loop, $pingTimer) {
            echo "连接已关闭:{$code} - {$reason}\n";
            $loop->cancelTimer($pingTimer);
            $loop->stop();
        });
    }, function (\Exception $e) use ($loop) {
        echo "连接失败:{$e->getMessage()}\n";
        $loop->stop();
    });
});

// 启动事件循环
$loop->run();
?>

3. 关键注意点

  • 事件名确认:代码中的joinScoring和scoringUpdate是假设的事件名,你需要打开浏览器开发者工具(Network -> WebSocket),查看网站实际发送和接收的事件名称,替换成对应的值。
  • Socket.IO版本:代码中使用的是EIO=4(对应Socket.IO v4),如果网站用的是其他版本,需要调整握手URL和消息格式。

内容的提问来源于stack exchange,提问作者truemiro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 20:52:34