B站flv视频解析播放

发现了一个有名的下载工具you-get,其中还有B站的视频解析源码
分析了大半天终于把B站的部分视频API找出来了
继上次用其他的解析网站间接获取视频地址,有一定的失败风险
这次就没问题了(除非B站的视频API接口换了)

阅读注意:我是懵新,不喜勿喷

项目需求

  • 视频解析相关api(必要)
  • 一个支持播放flv文件的flv.js(必要)
  • php基础及其curl知识

项目思路

1.提供B站视频地址av
2.获取av对应cid进而获取地址api接口
3.获取api地址返回的json字符串
4.截取json字符串中视频地址
5.用curl输出flv文件同化为php文件
6.用flv.js项目播放php同化的视频

项目测试

可到实验菜单中查看

项目源码

点此访问Github

初代

index.php

<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<title>flv解析</title>
<style>
.mainContainer {
display: block;
width: 1024px;
margin-left: auto;
margin-right: auto;
}
.urlInput {
display: block;
width: 100%;
margin-left: auto;
margin-right: auto;
margin-top: 8px;
margin-bottom: 8px;
}
.centeredVideo {
display: block;
width: 100%;
height: 576px;
margin-left: auto;
margin-right: auto;
margin-bottom: auto;
}
.controls {
display: block;
width: 100%;
text-align: left;
margin-left: auto;
margin-right: auto;
}
</style>
</head>
<body>
<?php
$file = "geturl.txt";
if(file_exists($file)){
//$msg = file_get_contents($file);//使用file_get_contents函数获取url
//$array = get_headers($msg,1);
//echo $array[0];//测试返回代码
//if(preg_match('/453/',$array[0])){//判断url453不可访问则为有效//如果upos返回403不可解析
//  } else {//url无效,getapi.php重写url
    include 'getapi.php';
//  echo "<script language=JavaScript> location.replace(location.href);</script>";//php刷新页面
//  }
}
?>
<div class="mainContainer">
<video id="videoElement" class="centeredVideo" controls autoplay width="1024" height="576"></video>

</div>
<br>
<div class="controls">
<!--<button onclick="flv_load()">加载</button>-->
<button onclick="flv_start()">开始</button>
<button onclick="flv_pause()">暂停</button>
<button onclick="flv_destroy()">停止</button>
<input style="width:100px" type="text" name="seekpoint" />
<button onclick="flv_seekto()">跳转</button>
</div>

<script src="./flv.min.js"></script>
<script>
      var player = document.getElementById('videoElement');
      if (flvjs.isSupported()) {
         var flvPlayer = flvjs.createPlayer({type: 'flv',//此处可添加设置
        url: 'flv.php',//<==自行修改
            }, {
        lazyLoadMaxDuration: 10 * 60 //前面数值对应单位缓存差18s//此处具体参数可以通过获得的视频具体时长计算
            });
            flvPlayer.attachMediaElement(videoElement);
            flvPlayer.load(); //加载
            flv_start();
        }
        function flv_start() {
            player.play();
        }
        function flv_pause() {
            player.pause();
        }
        function flv_destroy() {
            player.pause();
            player.unload();
            player.detachMediaElement();
            player.destroy();
            player = null;
        }
        function flv_seekto() {
            player.currentTime = parseFloat(document.getElementsByName('seekpoint')[0].value);
        }
</script>
</body>
</html>

getapi.php

<?php
$av = "810872";//视频的av编号
$cid = getcid($av);
$api = getapi($cid);
$msg = getjson($api);
//echo $api;//测试视频api能否解析
$result=array();
preg_match_all("/(?:http)(.*)(?:backup_url)/i",$msg, $result);//匹配url大致字符串
$flvurl = $result[1][0];
$flvurl = substr($flvurl, 0, strlen($flvurl)-3);
$flvurl = "http".$flvurl;
writeurl("geturl.txt" ,$flvurl);
function getcid($av) {//已知av获取cid
    $api = "http://api.bilibili.com/view?type=&appkey=84956560bc028eb7&id=".$av;
    $json = getjson($api);
    $result=array();
    preg_match_all("/(?:cid)(.*)(?:partname)/i",$json, $result);//匹配cid大致字符串
    $cid = $result[1][0];
    $cid = substr($cid, 2, strlen($cid)-4);//加工截取得到cid
    return $cid;
}
function getapi($cid) {//核心代码————解析函数
    $q = "80";//数值表示清晰度(112|1080P+)/(80->1080P)/(64->720)/(32->480P)/(16->360P)//以最后返回为准,可能存在误差
    $SEC1 = "94aba54af9065f71de72f5508f1cd42e";//特殊密钥
    $api_url = "http://interface.bilibili.com/v2/playurl?";//去v2清晰度最高480或(64->720)
    $params_str = "appkey=84956560bc028eb7&cid=".$cid."&otype=json&qn=".$q."&quality=".$q."&type=flv";
    $sign = md5($params_str.$SEC1);
    $api_url = $api_url.$params_str."&sign=".$sign;
    return $api_url;
}
function getjson($url) {
    $curl = curl_init();//创建一个新的CURL资源
    $headers = randIp();
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);//伪造请求ip
    curl_setopt ($curl, CURLOPT_REFERER, "http://bilibili.com");//伪造请求源referer
    curl_setopt($curl,CURLOPT_URL,$url);//设置URL和相应的选项
    curl_setopt($curl,CURLOPT_HEADER,0);//0表示不输出Header,1表示输出
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);//数据不输出到页面
    curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
    curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,false);
    curl_setopt($curl,CURLOPT_ENCODING,'');//设置编码格式,为空表示支持所有格式的编码//header中“Accept-Encoding: ”部分的内容,支持的编码格式为:"identity","deflate","gzip"
    $UserAgent="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36";
    curl_setopt($curl,CURLOPT_USERAGENT,$UserAgent);//模拟windows用户正常访问
    //错误curl_setopt($curl,CURLOPT_FOLLOWLOCATION,1);//设置这个选项为一个非零值(象 “Location: “)的头,服务器会把它当做HTTP头的一部分发送(注意这是递归的,PHP将发送形如 “Location: “的头)
    $json = curl_exec($curl);
    curl_close($curl);
    return $json;
}
function writeurl($TxtFileName,$url) {//服务器存放写入url的txt文件(名称,字符串)
    if(($TxtRes=fopen($TxtFileName,"w+")) === FALSE){//以读写方式打写指定文件,如果文件不存则创建
    //创建可写文件$TxtFileName失败
    exit();
    }
    //创建可写文件$TxtFileName成功
    $StrConents = $url;//要写进文件的内容
    if(!fwrite($TxtRes,$StrConents)) {//将信息写入文件
    //尝试向文件$TxtFileName写入$StrConents失败
    fclose($TxtRes);
    exit();
    }
    //尝试向文件$TxtFileName写入$StrConents成功!
    fclose($TxtRes); //关闭指针
}
function randIP(){//随机ip
       $ip_long = array(
           array('607649792', '608174079'), //36.56.0.0-36.63.255.255
           array('1038614528', '1039007743'), //61.232.0.0-61.237.255.255
           array('1783627776', '1784676351'), //106.80.0.0-106.95.255.255
           array('2035023872', '2035154943'), //121.76.0.0-121.77.255.255
           array('2078801920', '2079064063'), //123.232.0.0-123.235.255.255
           array('-1950089216', '-1948778497'), //139.196.0.0-139.215.255.255
           array('-1425539072', '-1425014785'), //171.8.0.0-171.15.255.255
           array('-1236271104', '-1235419137'), //182.80.0.0-182.92.255.255
           array('-770113536', '-768606209'), //210.25.0.0-210.47.255.255
           array('-569376768', '-564133889'), //222.16.0.0-222.95.255.255
       );
       $rand_key = mt_rand(0, 9);
       $ip= long2ip(mt_rand($ip_long[$rand_key][0], $ip_long[$rand_key][1]));
       $headers['CLIENT-IP'] = $ip; 
       $headers['X-FORWARDED-FOR'] = $ip; 
       $headerArr = array(); 
       foreach( $headers as $n => $v ) { 
           $headerArr[] = $n .':' . $v;  
       }
       return $headerArr;    
   }
?>

flv.php

<?php
$file = "geturl.txt";
if(file_exists($file)){
$url1 = file_get_contents($file);//使用file_get_contents函数获取url
$curl = curl_init();//创建一个新的CURL资源
$headers = randIp();
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);//伪造请求ip
curl_setopt ($curl, CURLOPT_REFERER, "http://bilibili.com");//伪造请求源referer
curl_setopt($curl,CURLOPT_URL,$url1);//设置URL和相应的选项
curl_setopt($curl,CURLOPT_HEADER,0);//0表示不输出Header,1表示输出
//curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);//flv与php同化,数据直接输出到页面
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,false);
curl_setopt($curl,CURLOPT_ENCODING,'');//设置编码格式,为空表示支持所有格式的编码//header中“Accept-Encoding: ”部分的内容,支持的编码格式为:"identity","deflate","gzip"
$UserAgent="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36";
curl_setopt($curl,CURLOPT_USERAGENT,$UserAgent);//模拟windows用户正常访问
//错误curl_setopt($curl,CURLOPT_FOLLOWLOCATION,1);//设置这个选项为一个非零值(象 “Location: “)的头,服务器会把它当做HTTP头的一部分发送(注意这是递归的,PHP将发送形如 “Location: “的头)
curl_exec($curl);
curl_close($curl);
}
function randIP(){//随机ip
       $ip_long = array(
           array('607649792', '608174079'), //36.56.0.0-36.63.255.255
           array('1038614528', '1039007743'), //61.232.0.0-61.237.255.255
           array('1783627776', '1784676351'), //106.80.0.0-106.95.255.255
           array('2035023872', '2035154943'), //121.76.0.0-121.77.255.255
           array('2078801920', '2079064063'), //123.232.0.0-123.235.255.255
           array('-1950089216', '-1948778497'), //139.196.0.0-139.215.255.255
           array('-1425539072', '-1425014785'), //171.8.0.0-171.15.255.255
           array('-1236271104', '-1235419137'), //182.80.0.0-182.92.255.255
           array('-770113536', '-768606209'), //210.25.0.0-210.47.255.255
           array('-569376768', '-564133889'), //222.16.0.0-222.95.255.255
       );
       $rand_key = mt_rand(0, 9);
       $ip= long2ip(mt_rand($ip_long[$rand_key][0], $ip_long[$rand_key][1]));
       $headers['CLIENT-IP'] = $ip;
       $headers['X-FORWARDED-FOR'] = $ip;
       $headerArr = array(); 
       foreach( $headers as $n => $v ) {
           $headerArr[] = $n .':' . $v;
       }
       return $headerArr;
   }
?>

我的记事本

1.0 php取代python内置函数
1.1 php返回时间戳1970起始秒数time()
1.2 php转换为字符串strval()
1.3 php字符串可自动化为数值
1.4 php点式连接字符串$a.$b
2.0 找到B站获取视频地址的API接口
2.1 删除v2的API清晰度受限flv480
2.2 视频地址无法播放只能json跳转下载
2.3 B站播放器播放原理
2.4 前端播放器进行缓存下载与播放???
3.0 改换为parsevideo.com解析方法???
3.1 逆向解析返回的实际超清mp4地址???
4.0 继续flv视频json数据的API
4.1 php伪造referer地址
4.2 curl返回疑似视频文件乱码
4.3 对比得返回数据为视频文件
4.4 curl下载返回数据为.flv
4.5 curl回调下载大型数据文件???
4.6 js伪造referer地址???
4.7 WinHttp.WinHttpRequest.5.1对象伪造referer???
4.8 js调用本地服务器php的curl伪造
5.0 前端播放flv视频数据流文件
5.1 JavaScript引用flv.js开源项目
5.2 从flv.js中获取flv.js文件(=-=)
5.3 应用flv.js播放服务端flv视频(=-=)
5.4 flv.js以php的curl返回数据播放
5.5 curl返回页面数据占用较大内存
5.6 使用函数或curl直接引用于url???
6.0 完善整体解析视频流程
6.1 获取返回json数据中的相关数据
6.2 php正则匹配json字符串
6.3 php截取字符串substr()函数
6.4 php判断url有效性调用php文件include方法
7.0 出现视频限制80s停止,视频下载至4分钟左右???
7.1 下载暂停与php的curl无关???
7.2 下载暂停似视频时间比例分段???
7.3 下载暂停原因播放进度距离下载进度过远
7.4 flv.js设置azyLoadMaxDuration时间(=-=)
7.5 出现与清晰度无关的未知镜头数据混乱花屏
7.6 镜头数据混乱花屏纯属视频源问题
8.0 不同服务器同一api返回不同json视频源403异常无法正常下载???
8.1 出现upos或cn-sh视频源403异常无法正常下载或被限速???
8.2 curl设置请求头伪装服务器???
8.3 改由前端js获取B站服务器json数据???
8.4 使用iframe伪前端获取B站服务器json数据
8.5 服务器防止iframe嵌入
8.5 改换服务器后视频可以解析播放
8.6 cn-jxjj返回数据出现视频源453转456异常下载限速

API公共版

见GitHub

点赞
  1. 波波说道:
    QQbrowser Android 7.1.2
    浩哥,你是个神仙吧,牛逼啊
    1. injahow injahow说道:
      Google Chrome Windows 10
      没想到还有人参观啊,吃惊,就是闲着没事研究了下

发表评论

电子邮件地址不会被公开。必填项已用 * 标注