解析网页版的播放接口原理,基于实战完整实现搜索、多音质获取、流式代理播放、歌词同步等细节。

一、碎

播放接口未对外开放,却可以通过开发者工具抓取分析。

记录一下网页版播放链路的逆向分析过程,以及 从零实现一个完整播放器 的全流程,包含:

  • 歌曲搜索(支持分页)
  • 多音质播放链接获取(FLAC / 320kbps / 128kbps / AAC)
  • 流式服务端代理绕过防盗链
  • 歌词实时获取与高亮同步
  • 自定义播放器 UI

免责声明: 本文仅用于技术研究学习,请尊重音乐版权,所得数据仅限个人测试使用。


二、起点:浏览器开发者工具

网络请求

打开 https://y.qq.com/,搜索任意歌曲,按 F12 → Network 面板。点击播放后,主要关注三类请求:

请求类型接口地址用途
搜索c.y.qq.com/soso/fcgi-bin/search_for_qq_cp获取歌曲元数据
播放凭证u.y.qq.com/cgi-bin/musicu.fcg POST获取 vkey 和 CDN 地址
音频文件isure.stream.qqmusic.qq.com/*实际音频流

搜索接口

GET https://c.y.qq.com/soso/fcgi-bin/search_for_qq_cp?w=七里香&p=1&n=20&format=json&platform=h5

返回 JSONP 格式数据,关键字段:


{
  "songname": "七里香",
  "songmid": "004Z8Ihr0JIu5s",
  "singer": [{"name": "周杰伦"}],
  "albummid": "003DFRzD192KKD"
}

songmid 是每首歌的唯一标识,后续所有接口都依赖它。albummid 用于拼接专辑封面 URL。

播放凭证(vkey)接口


POST https://u.y.qq.com/cgi-bin/musicu.fcg
Content-Type: application/json

请求体:

{
  "req_0": {
    "module": "vkey.GetVkeyServer",
    "method": "CgiGetVkey",
    "param": {
      "filename": ["M500004Z8Ihr0JIu5s004Z8Ihr0JIu5s.mp3"],
      "guid": "a9444620715462ea",
      "songmid": ["004Z8Ihr0JIu5s"],
      "songtype": [0],
      "uin": "0",
      "loginflag": 1,
      "platform": "20"
    }
  },
  "comm": { "uin": 0, "format": "json", "ct": 19, "cv": 0 }
}

filename 格式规则: {音质前缀}{songmid}{songmid}.{后缀}

前缀后缀音质歌曲大小
F000.flac无损 FLAC~30MB
M800.mp3高品质 320kbps~10MB
M500.mp3标准 128kbps~4MB
C400.m4aAAC 格式~3MB

响应中关键返回结构(两种历史格式需兼容):

格式一(midurlinfo):

{
  "midurlinfo": [{"purl": "M500xxx.mp3?vkey=7D54ACE0&guid=xxx&uin=6841847"}],
  "sip": ["https://isure.stream.qqmusic.qq.com/"]
}

最终 URL = sip[0] + midurlinfo[0].purl

格式二(testfile2g):


{
  "testfile2g": "C400xxx.m4a?guid=xxx&vkey=7D54ACE0",
  "sip": ["http://aqqmusic.tc.qq.com/"]
}

最终 URL = sip[0] + testfile2g(注意 HTTP → HTTPS的转换)


三、GUID 与 Cookie

GUID 生成

GUID 是 16 位随机十六进制字符串,没有校验逻辑,每次请求可随机生成:


$guid = substr(md5(uniqid(mt_rand(), true)), 0, 16);

不同Cookie的作用

状态作用音质
无 Cookie❌ 被 CDN 拦截无法播放音乐
无会员 Cookie✅ 可试听128kbps
无会员 Cookie✅ 完整播放免费歌曲320kbps
VIP Cookie✅ 完整播放FLAC 无损

Cookie 中关键字段:uin(QQ号)、qqmusic_key(登录态密钥)。有效期暂未测试过。


四、防盗链跟快速代理

Referer检查

CDN 检查 HTTP Referer 头——只有来自 y.qq.com 的请求才被允许。浏览器 <audio> 标签无法自定义 Referer,所以需要服务端代理。

否则提示:禁止跨域访问

转发代理

传统代理使用 file_get_contents 下载完整文件后再输出,延迟大(几十秒)。优化方案是使用 fopen + fpassthru 边下载边转发


$fp = @fopen($url, 'rb', false, stream_context_create([
    'http' => ['header' => "User-Agent: Mozilla/5.0\r\nReferer: https://y.qq.com/"]
]));
if ($fp) {
    fpassthru($fp);  
    fclose($fp);
}

这样浏览器在收到第一个数据包后就可以开始缓冲播放,延迟从数十秒降到 1-3 秒。

4.3 代理流程


┌─────────┐  src="proxy.php?url=..."  ┌──────────┐  fopen+fpassthru  ┌──────────────┐
│ Browser │ ←──────────────────────── │ PHP Proxy│ ←─────────────── │ QQ Music CDN │
│         │      流式音频数据          │          │  带 Referer 请求  │              │
└─────────┘                          └──────────┘                   └──────────────┘

五、完整实现

HTTP工具


function http_get($url, $referer = 'https://y.qq.com/') {
    $ctx = stream_context_create([
        'http' => [
            'method' => 'GET',
            'header' => "User-Agent: Mozilla/5.0\r\nReferer: $referer\r\n",
            'timeout' => 10
        ],
        'ssl' => ['verify_peer' => false, 'verify_host' => false]
    ]);
    return @file_get_contents($url, false, $ctx);
}

function http_post($data, $cookie = '') {
    $json = json_encode($data);
    $header = "User-Agent: Mozilla/5.0\r\n"
            . "Referer: https://y.qq.com/\r\n"
            . "Content-Type: application/json\r\n"
            . "Content-Length: " . strlen($json);
    if ($cookie) $header .= "\r\nCookie: " . $cookie;

    $ctx = stream_context_create([
        'http' => ['method' => 'POST', 'header' => $header, 'content' => $json, 'timeout' => 8],
        'ssl' => ['verify_peer' => false, 'verify_host' => false]
    ]);
    return @file_get_contents("https://u.y.qq.com/cgi-bin/musicu.fcg", false, $ctx);
}

搜索接口实现


$kw = $_GET['w'];
$page = $_GET['p'] ?? 1;

$resp = http_get("https://c.y.qq.com/soso/fcgi-bin/search_for_qq_cp?" . http_build_query([
    'w' => $kw, 'p' => $page, 'n' => 20, 'format' => 'json',
    'platform' => 'h5', 'g_tk' => '5381', 'uin' => '0'
]));

if (preg_match('/^[A-Za-z_]+\((.*)\)$/s', $resp, $m)) $resp = $m[1];

$data = json_decode($resp, true);
$songs = $data['data']['song']['list'] ?? [];

返回的 albummid 用于拼接封面图 URL:https://y.qq.com/music/photo_new/T002R300x300M000{albummid}.jpg

不同音质的获取

每个音质独立请求 vkey 接口,按优先级排序:
从响应中提取 midurlinfo / testfile2g
构造完整播放 URL 并收集到 $urls 数组


$fmtList = [
    ['F000', '.flac',  '无损FLAC'],
    ['M800', '.mp3',   '高品质320kbps'],
    ['M500', '.mp3',   '标准128kbps'],
    ['C400', '.m4a',   'AAC'],
];

foreach ($fmtList as $fmt) {
    $body["req_0"]["param"]["filename"] = [$fmt[0] . $mid . $mid . $fmt[1]];
    $resp = http_post($body, $cookie);
    
}

歌词获取


$resp = http_get(
    "https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?"
    . "songmid={$mid}&pcachetime=" . round(microtime(true) * 1000)
);

$d = json_decode($resp, true);
$lyricRaw = base64_decode($d['lyric']);

// 解析 LRC 格式
preg_match_all('/\[(\d{2}):(\d{2})\.(\d{2,3})\](.*)/', $lyricRaw, $m, PREG_SET_ORDER);
foreach ($m as $v) {
    $ms = intval($v[3]);
    if (strlen($v[3]) == 2) $ms *= 10;  // 2位毫秒 → 补成3位
    $lines[] = [
        't' => intval($v[1])*60 + intval($v[2]) + $ms/1000,
        'c' => trim($v[4])
    ];
}

音频代理


if ($action == 'proxy') {
    $url = $_GET['url'];
    $hdr = "User-Agent: Mozilla/5.0\r\nReferer: https://y.qq.com/";
    if ($cookie) $hdr .= "\r\nCookie: " . $cookie;

    $fp = @fopen($url, 'rb', false, stream_context_create([
        'http' => ['method' => 'GET', 'header' => $hdr, 'timeout' => 60],
        'ssl'  => ['verify_peer' => false, 'verify_host' => false]
    ]));
    if ($fp) { fpassthru($fp); fclose($fp); }
    exit;
}

点击图片查看下一张

六、前端实现要点

播放器ui扔给AI处理就行了

歌词同步

前端通过 ontimeupdate 事件(每 250ms)获取播放进度,匹配歌词时间戳:


audio.ontimeupdate = function() {
    var cur = audio.currentTime;

    for (var i = lyrics.length - 1; i >= 0; i--) {
        if (lyrics[i].t <= cur + 0.3) {
            lines[i].style.color = "#007aff";
            lines[i].scrollIntoView({block: "center"});
            break;
        }
    }
};

API 返回的播放链接包含 vkeyuinguid 等敏感信息,展示到调试面板前进行脱敏处理


cookies请自己F12网页登录抓取,复制整个cookies值,粘贴到下面文件的头部

本文对应完整单文件实现可在配套的 qqmusic-demo.php 查看。该文件集成了搜索、多音质获取、流式代理、歌词同步、自定义播放器等全部功能,可直接部署运行。

网盘规则,下载后删除.txt后缀

下载地址