点击 这里 查看在线 demo
随机打开一个视频,抓包
搜索 mp4,发现这个 m3u8 文件请求,所有的视频片段都在这里面
继续搜索 m3u8 文件的地址,可以发现是从这个 API 里出来的
地址是 https://acs.youku.com/h5/mtop.youku.play.ups.appinfo.get/1.1/
看一下参数:
还是挺多的…
经过筛选之后,其实只需要这些参数
其中 appkey
、api
固定,t
应该与时间有关(时间戳)
将 data
整理后得到:
{
"steal_params": "{\"ccode\":\"0502\",\"client_ip\":\"192.168.1.1\",\"utid\":\"NBevFStAZEQCAW40jnu9IcNS\",\"client_ts\":1566290208,\"version\":\"1.8.1\",\"ckey\":\"119#MlKT3NBFM8PGzMMzlyfMRuVLT7EBEbACc6MtYBAsqUnTFatOwvVDvYyAjcplNL8GLeASRBsU3AALuwHNk9SKOrA8RJBONt8L9ei25SSUdGIy/Upp4SMn6rA2RW1zNNFGfeAzR/QYdUeIx4LL7G12qCnxSCqOfoDjsvmw6EOMAOl7Y/h6SYVHIxImmtyIKrTJDojBBgjZTamxD7tViyQxxP+C3W/fByo7iM3PGDP3dzMNrb0Y96bE7k8oJV6e6IaFwcLCuRUspdmc4zcGhpzU4m/8TqqD0cuYnEwbg+pQHpkBd9ALU3j6uFCi9h6jIaRrpTSV7kwAur6WcTODqT1B4d6/MJ9eFwkMZrVn5MabjVXDbKcnmaGmL9aj/4k1yfWkCY0YNhREFvU7N/slngR/mgjDBGPBvvm5CR4PHRrTE4c7DCfnW/xEW31J19xRLyc2P48mIQM2LQxfw2cBJhCDrxZXJBEWyA3XplF7/8a9D5z0BU0THL6GE4ec/ru6n9yNWaSMq5mY/uJNNf9wh3GymAu4hJTGV35dOFSIhSrYsMa3r/Icy4BmbcxCzxIw9f4xqeQxFBo8d8501Zl2vKkrOO2WMrom3RkH1OBfOLUwjPSJqOZ1Y7HFSE0RkD+FHtNhZdE1bTjG3FW56JBXao90g1tWjedX+Q14g9QTbhVSrzkXBbMUIC==\"}",
"biz_params": "{\"vid\":\"XNDMxNzkyNjY2OA==\",\"play_ability\":5376,\"master_m3u8\":1,\"media_type\":\"standard,subtitle\",\"app_ver\":\"1.8.1\"}",
"ad_params": "{\"vs\":\"1.0\",\"pver\":\"1.8.1\",\"sver\":\"2.0\",\"site\":1,\"aw\":\"w\",\"fu\":0,\"d\":\"0\",\"bt\":\"pc\",\"os\":\"win\",\"osv\":\"7\",\"dq\":\"auto\",\"atm\":\"\",\"partnerid\":\"null\",\"wintype\":\"interior\",\"isvert\":0,\"vip\":0,\"emb\":\"AjEwNzk3MDM3NzMCdi55b3VrdS5jb20CL3Zfc2hvdy9pZF9YTkRNeE9EZ3hOVEE1TWc9PS5odG1s\",\"p\":1,\"rst\":\"mp4\",\"needbf\":2}"
}
其中有视频的 ID XNDMxNzkyNjY2OA==
,说明真实参数应该放这里面
为了方便,这里使用 fiddler 替换 youku-player.min.js
为修改后的 js
保存 youku-player.min.js
到本地,在最上方加上一条提示:
在 fiddler 中设置好,具体可以参考百度
刷新,修改成功!
那么就剩下 sign
了
经过一段时间的搜索,在 youku-player.min.js
中发现 sign 的位置
其中:
sign = u = s(i.token + "&" + l + "&" + o + "&" + n.data);
s()
函数暂时不管,先搞清楚参数
l
就是时间戳
o
就是 appkey
输出 appkey
与请求中的 appkey
是一样的
输出n.data
,看看是什么
可见 n.data
就是请求里的 data
用同样的方法,输出 i.token
最后在 Cookie 中搜索到了 token 的内容
那这个 Cookie 又是哪来的?
搜索发现,不带 Cookie 调用此 API 就会返回 Cookie
参数都知道了,再看看 s()
函数
输出一下返回的内容
经过比较 sign 参数的确是这个
那么,s()
函数在哪??
在整个 js 中搜索太费时间,这里换一种方法
不传参数直接调用:
不传参数必然会抛异常,此时再去控制台看看
果然有了!
转到 s()
函数
…(╯°Д°)╯
后来突然想到 sign
会不会就是 md5
结果发现还真的是 md5
所以,sign
的算法是:
const appkey = 24679788;
var token = 在_Cookie_m_h5_tk_中获取();
var sign = md5(token + "&" + 时间戳 + "&" + appkey + "&" + 参数json);
写段 PHP 来测试一下
<meta charset="utf-8" />
$url = "http://acs.youku.com/h5/mtop.youku.play.ups.appinfo.get/1.1/?";
$appkey = "24679788";
$token = "5244eaea528c0c41bfdcea84251eb1ab"; //不要直接用这个 token,你看到的时候已经过期了
$time = time();
$data = file_get_contents("data");
//拼接参数
$params = array(
"appKey" => $appkey,
"t" => $time,
"sign" => md5($token."&".$time."&".$appkey."&".$data),
"api" => "mtop.youku.play.ups.appinfo.get",
"data" => $data
);
echo "data_sign="
.$token."&".$time."&".$appkey."&".$data."
";
echo "sign=".$params["sign"].""; $url = $url.http_build_query($params); $ch = curl_init($url); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); //返回内容储存到变量中 $data = curl_exec($ch); echo "
".$data.""; ?>
这是 data 文件里的内容
{
"steal_params": "{\"ccode\":\"0502\",\"client_ip\":\"192.168.1.1\",\"utid\":\"NBevFStAZEQCAW40jnu9IcNS\",\"client_ts\":1566290208,\"version\":\"1.8.1\",\"ckey\":\"119#MlKT3NBFM8PGzMMzlyfMRuVLT7EBEbACc6MtYBAsqUnTFatOwvVDvYyAjcplNL8GLeASRBsU3AALuwHNk9SKOrA8RJBONt8L9ei25SSUdGIy/Upp4SMn6rA2RW1zNNFGfeAzR/QYdUeIx4LL7G12qCnxSCqOfoDjsvmw6EOMAOl7Y/h6SYVHIxImmtyIKrTJDojBBgjZTamxD7tViyQxxP+C3W/fByo7iM3PGDP3dzMNrb0Y96bE7k8oJV6e6IaFwcLCuRUspdmc4zcGhpzU4m/8TqqD0cuYnEwbg+pQHpkBd9ALU3j6uFCi9h6jIaRrpTSV7kwAur6WcTODqT1B4d6/MJ9eFwkMZrVn5MabjVXDbKcnmaGmL9aj/4k1yfWkCY0YNhREFvU7N/slngR/mgjDBGPBvvm5CR4PHRrTE4c7DCfnW/xEW31J19xRLyc2P48mIQM2LQxfw2cBJhCDrxZXJBEWyA3XplF7/8a9D5z0BU0THL6GE4ec/ru6n9yNWaSMq5mY/uJNNf9wh3GymAu4hJTGV35dOFSIhSrYsMa3r/Icy4BmbcxCzxIw9f4xqeQxFBo8d8501Zl2vKkrOO2WMrom3RkH1OBfOLUwjPSJqOZ1Y7HFSE0RkD+FHtNhZdE1bTjG3FW56JBXao90g1tWjedX+Q14g9QTbhVSrzkXBbMUIC==\"}",
"biz_params": "{\"vid\":\"XNDMxNzkyNjY2OA==\",\"play_ability\":5376,\"master_m3u8\":1,\"media_type\":\"standard,subtitle\",\"app_ver\":\"1.8.1\"}",
"ad_params": "{\"vs\":\"1.0\",\"pver\":\"1.8.1\",\"sver\":\"2.0\",\"site\":1,\"aw\":\"w\",\"fu\":0,\"d\":\"0\",\"bt\":\"pc\",\"os\":\"win\",\"osv\":\"7\",\"dq\":\"auto\",\"atm\":\"\",\"partnerid\":\"null\",\"wintype\":\"interior\",\"isvert\":0,\"vip\":0,\"emb\":\"AjEwNzk3MDM3NzMCdi55b3VrdS5jb20CL3Zfc2hvdy9pZF9YTkRNeE9EZ3hOVEE1TWc9PS5odG1s\",\"p\":1,\"rst\":\"mp4\",\"needbf\":2}"
}
结果“令牌为空”?
{"api":"mtop.youku.play.ups.appinfo.get","data":{},"ret":["FAIL_SYS_TOKEN_EMPTY::令牌为空"],"v":"1.1"}
把 Cookie 也带上
//经过测试,只需要这两个 Cookie
//不要直接用这个 cookie,原因同上
$cookie = "_m_h5_tk=5244eaea528c0c41bfdcea84251eb1ab_1566446442446; _m_h5_tk_enc=789e5077a464542c59b8825eaaa7823e; Domain=youku.com";
//......
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
刷新,换了个错误:“客户端无权播放”
{"ret":["SUCCESS::调用成功"],"data":{"cost":0.009000000543892384,"data":{"error":{"note":"客户端无权播放,201","code":-6004}},"e":{"code":0,"provider":"hsfprovider","desc":""}},"v":"1.1","api":"mtop.youku.play.ups.appinfo.get"}
再带上 UA
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36"); //设置 UA
结果还是不行??
{"ret":["SUCCESS::调用成功"],"data":{"cost":0.009000000543892384,"data":{"error":{"note":"客户端无权播放,201","code":-6004}},"e":{"code":0,"provider":"hsfprovider","desc":""}},"v":"1.1","api":"mtop.youku.play.ups.appinfo.get"}
Referer 也带上
curl_setopt($ch, CURLOPT_REFERER, "https://v.youku.com/v_show/id_XNDMxODgxNTA5Mg==.html");
这次调用成功,返回的 json 很长
说明 data
里只需要改 vid
参数就可以
其中 data.data.preview.thumb_hd[0]
貌似是视频各个时间点的截图
图片内容:
data.data.ad
下是广告地址
data.data.video
下是视频信息
data.data.stream[n]
下面就是各个清晰度的视频地址
其中 mp4hd3v2
就是 1080P 的地址
一些错误信息的解决方法
信息 | 解决方法/原因 |
---|---|
账号异常,请重新登录 | 大概是请求频率太快,尝试清除/更换 Cookie,稍后重试 |
令牌为空/过期 | 你的 Cookie 没传/过期了 |
非法请求 | 某个参数错了(比如 sign 算错了) |
http响应缺少参数api | data 里缺少了某个参数 |
点这里