解析网页版的播放接口原理,基于实战完整实现搜索、多音质获取、流式代理播放、歌词同步等细节。
一、碎
播放接口未对外开放,却可以通过开发者工具抓取分析。
记录一下网页版播放链路的逆向分析过程,以及 从零实现一个完整播放器 的全流程,包含:
- 歌曲搜索(支持分页)
- 多音质播放链接获取(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 | .m4a | AAC 格式 | ~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 返回的播放链接包含 vkey、uin、guid 等敏感信息,展示到调试面板前进行脱敏处理
cookies请自己F12网页登录抓取,复制整个cookies值,粘贴到下面文件的头部
本文对应完整单文件实现可在配套的 qqmusic-demo.php 查看。该文件集成了搜索、多音质获取、流式代理、歌词同步、自定义播放器等全部功能,可直接部署运行。
网盘规则,下载后删除.txt后缀
评论(暂无评论)