說來慚愧,雖然申請部落格是兩三年前的事情了
但是真的開始有用的習慣也是前幾個月才開始的
------------------------------------------------
今天因老師請託要下載youtube的影片
我就藉這個機會來研究他的原理
目前網路上的教學大概都是找出實體檔案的方式來下載youtube的檔案
常用程式碼如下
JavaScript
一般FLV畫質 (貼上以下全段不要斷行就會出現下載)
javascript:window.location.href = 'http://youtube.com/get_video?video_id=' +
swfArgs['video_id'] + "&l=" + swfArgs['l'] + "&sk=" + swfArgs['sk'] + '&t=' +
swfArgs['t'];
HQ畫質 (貼上以下全段不要斷行就會出現下載)
javascript:window.location.href = 'http://youtube.com/get_video?video_id=' +
swfArgs['video_id'] + "&fmt=18" + "&l=" + swfArgs['l'] + "&sk=" +
swfArgs['sk'] + '&t=' + swfArgs['t'];
HD畫質 (貼上以下全段不要斷行就會出現下載)
javascript:window.location.href = 'http://youtube.com/get_video?video_id=' +
swfArgs['video_id'] + "&fmt=22" + "&l=" + swfArgs['l'] + "&sk=" +
原文網址
但是我覺得光這樣太無趣了點,於是在去研究了一下原理
開了Fiddler去看一下封包
youtube實體影片是像其底下的get_video這網頁要來的(其實看上面javascript碼就知道了)
他帶了許多參數,後來發現,如果不考慮畫面,直接下載純影像的話
其實必備只須要下面兩個參數就夠了
- video_id
- t
舉個例子
http://www.youtube.com/watch?v=hjTb2gR8rpE&feature=related
隨便開啟一個youtube影片,打開他的HTML原始碼觀看
之後找到flash影片參數的部分,也就是 swfArgs的部分
這部份知識請去摸一下flash就會知道了
var swfArgs = {"usef": 0, "fexp": "903900", "enablecsi": "1", "watermark": "http://s.ytimg.com/yt/swf/logo-vfl106645.swf,http://s.ytimg.com/yt/swf/hdlogo-vfl100714.swf", "sourceid": "yw", "video_id": "hjTb2gR8rpE", "l": 15, "fmt_map": "18/512000/9/0/115,34/0/9/0/115,5/0/7/0/0", "feature": "related", "sk": "nZDATrs2t38ie9xRcRK_a3mjI-RuKXhPC", "is_doubleclick_tracked": "1", "vq": null, "t": "vjVQa1PpcFPKYZQWD4_9jBe0ngheWegeZ2fbI7T0wM4=", "hl": "zh_TW", "plid": "AARv6bNtawhBJVmH", "keywords": "%E6%96%B0%E4%B8%96%E7%B4%80%E3%82%A8%E3%83%B4%E3%82%A1%E3%83%B3%E3%82%B2%E3%83%AA%E3%82%AA%E3%83%B3%2C%E7%B6%BE%E6%B3%A2%E8%82%B2%E6%88%90%E8%A8%88%E7%94%BB%2C%E3%82%A2%E3%82%B9%E3%82%AB%E8%A3%9C%E5%AE%8C%E8%A8%88%E7%94%BB%2CPS2", "cr": "TW", "fmt_url_map": "18%7Chttp%3A//v22.lscache7.c.youtube.com/videoplayback%3Fip%3D0.0.0.0%26sparams%3Did%252Cexpire%252Cip%252Cipbits%252Citag%252Cburst%252Cfactor%26itag%3D18%26ipbits%3D0%26signature%3D12986C2C910D07BD87B445AE1164DDDC8330C06A.4AC1217E49AC790C83083037590C528C82E6A187%26sver%3D3%26expire%3D1248973200%26key%3Dyt1%26factor%3D1.25%26burst%3D40%26id%3D8634dbda047cae91%2C34%7Chttp%3A//v3.lscache8.c.youtube.com/videoplayback%3Fip%3D0.0.0.0%26sparams%3Did%252Cexpire%252Cip%252Cipbits%252Citag%252Cburst%252Cfactor%26itag%3D34%26ipbits%3D0%26signature%3D1B606B2E46C0471A611386C163B6B18FB617D7AD.0CA6C95A06F6D8E55C99A4552B4066CB1CD541C6%26sver%3D3%26expire%3D1248973200%26key%3Dyt1%26factor%3D1.25%26burst%3D40%26id%3D8634dbda047cae91%2C5%7Chttp%3A//v6.lscache2.c.youtube.com/videoplayback%3Fip%3D0.0.0.0%26sparams%3Did%252Cexpire%252Cip%252Cipbits%252Citag%252Cburst%252Cfactor%26itag%3D5%26ipbits%3D0%26signature%3D14E5E77EB01FE7F0152AA1318492DFBDE6A42BA5.CA1E4504117C976ECC479DFF573BD96E3E9685D4%26sver%3D3%26expire%3D1248973200%26key%3Dyt1%26factor%3D1.25%26burst%3D40%26id%3D8634dbda047cae91", "sdetail": "f%3Arelated%2Crv%3A2yRxIwkBelc"};
他裡面帶很多參數,但是在此我們把問題簡化,只關心裡面的video_id跟t參數
.......
"video_id": "hjTb2gR8rpE"
"t": "vjVQa1PpcFPKYZQWD4_9jBe0ngheWegeZ2fbI7T0wM4="
......
之後我們只要把這兩個參數合併到youtube的網址就可以直接下載檔案如下
http://www.youtube.com/get_video?video_id=hjTb2gR8rpE&t=vjVQa1PpcFPKYZQWD4_9jBe0ngheWegeZ2fbI7T0wM4=
之後把他放到網址列按enter就可以下載影片了
那我們是否可以把這個工作自動化呢
當然可以,了解原理後,剩下的就只是字串處裡的問題而已
如何把兩個參數給抓出來
在此我們用jQuery+PHP實作一個簡單的範例
首先須要一個html檔當界面來接受我們網址的輸入
<body>
<input id="url" type="text" />
<input type="button" value="Get" onclick="getFlv();" />
</body>
再簡單不過的一個範例,一個textbox跟一個button
用一個function,getFlv()來處理我們的需求
而jQuery的部分也很單純
function getFlv(){
var url=$('#url').get(0).value;
$.post("getYouyube.php",{'url':url},function(data){
location.href='http://www.youtube.com/get_video?'+data
});
}
首先使用$('#url')或得textbox,並用get函式把他從jQuery物件轉成DOM物件
這樣我們才能抓取他的value
之後用一個post的請求給我們處裡字串的程式 getYouyube.php(這邊我打錯字 但是我也不想改了)
送一個參數url,也就是我們輸入的youtube網址
之後用location.href轉址就可以自動下載了
至於PHP的部分,他只是一些字串處裡而已
$html=file_get_contents($_POST['url']);
$arr=split("\n",$html);
$num=count($arr);
for($i=0;$i<$num;$i++)
{
if(ereg("swfArgs",$arr[$i]))
{
getArgs($arr[$i]);
}
}
首先用file_get_contents得到輸入網址的HTML原始碼
之後把它切割成一行一行的陣列 直到找到我們的目標swfArgs為止
之後我們用一個自定函式getArgs去抓出我們要的參數 video_id跟t
function getArgs($text)
{
$arr=split(",",$text);
$num=count($arr);
for($i=0;$i<$num;$i++)
{
$key=strtok($arr[$i],':');
$value=stripShell(strtok(':'));
if(strcmp(trim($key),"\"video_id\"")==0)
{
echo sprintf("%s=%s&",stripShell($key),$value);
}
else if(strcmp(trim($key),"\"t\"")==0)
{
echo sprintf("%s=%s&",stripShell($key),$value);
}
}
}
/*去頭尾字元*/
function stripShell($str)
{
return substr($str,2,-1);
}
結果展示
功能非常陽春,而且是適用於目前的youtube
他以後若改版之類的就不保證啦
不過可以根據參數這部份來提供更多服務,譬如說畫質選擇、檔名等等
這部份就以後再說吧