難得我母親要我給她下音樂聽,她在好聽音樂網(wǎng)上聽到一首,我就要百度好久才能找到播放的是哪首,好長時間才下了僅僅的幾首。
記得以前迅雷可以直接分析出下載地址來的,可是現(xiàn)在不知怎么的,迅雷的版本高了,功能卻變得弱智了。
沒有辦法就只有自己找找規(guī)律分析一下了,下面記錄我的分析過程,貼出來紀念下:
先看下網(wǎng)址的規(guī)律:
多個歌曲連播的URL地址形式:
http://www.haoting.com/play/htsonglian1.htm?id=123907&id=357857
其中id=后面的數(shù)字就是歌曲的ID。
單首歌曲播放的URL形式:
http://www.haoting.com/htmusic/357857ht.htm
其中的數(shù)字就是歌曲的ID。
查看其源文件,得到如下內(nèi)容:
<SCRIPT language="JavaScript" src="/js/lianbohy.js"></SCRIPT>
打開這個文件,查看其代碼,仔細分析得到有用信息如下:
function digui(musicids,length)
{
if(idindex < length)
{
idvalue = musicids[idindex];
s = document.createElement("script");
s.type="text/javascript";
s.src="http://haoting.com/musicjs/"+musicids[idindex]+".js"; // 這個是關(guān)鍵。
document.getElementsByTagName("head")[0].appendChild(s);

}

}
由于到這里兩種網(wǎng)址中歌曲的ID已經(jīng)都取到了只要訪問如下格式的URL:
http://haoting.com/musicjs/歌曲的ID.js
比如:
http://haoting.com/musicjs/357857.js
就可以下載到如下內(nèi)容的JS文件:
var url_357857="/21z/0/dianxiao2yyyyqx090620/1/0897053676a18e5e_1.wma"; //下載地址
var music_357857="相愛后動物感傷(CD Version) - 阿密特(張惠妹)"; //這個是歌曲名
var singer_357857="最新單曲"; //這個是歌手名
var nclassid_357857=5538;
var specialid_357857="abb60fe6d6c77f45";
var specialName_357857="最新單曲合輯NO.48"; //這個是專輯名
我們知道這個音樂在網(wǎng)站上的相對地址了,怎么才能知道它完整的地址呢?
繼續(xù)分析lianbohy.js中的代碼,找到如下信息:
//播放歌曲
function play(str,obj)
{

var STAND_STR = "/19z/",
STAND_STR2 = "/20z/",
STAND_STR3 = "/21z/",
STAND_STR4 = "/22z/";
if(url.indexOf(STAND_STR)==-1 && url.indexOf(STAND_STR2)==-1 && url.indexOf(STAND_STR3)==-1 && url.indexOf(STAND_STR4)==-1)
ht = "http://ow.haoting.com";
else
ht = "http://wma.haoting.com";
if(window.navigator.userAgent.indexOf("MSIE") == -1)
{
installPlayer(ht+url);
}
else
{
haotingplay.url=ht+url;
haotingplay.controls.play();
showTLab();
}

}
嘿嘿,明白了吧,如果看不懂這些代碼,就把它跟我們找到的地址一起對比下:
STAND_STR3 = "/21z/",
ht = " haotingplay.url=ht+url;
再看下相對地址:
var url_357857="/21z/0/dianxiao2yyyyqx090620/1/0897053676a18e5e_1.wma";
根據(jù)上面的文件我們可以提取出很多的信息,其中下載地址如下:
http://wma.haoting.com/21z/0/dianxiao2yyyyqx090620/1/0897053676a18e5e_1.wma
分析完畢,下面開始寫個小程序,讓它自動完成我上面的分析過程并顯示結(jié)果:
首先需要用程序來分解上面的網(wǎng)址,從中提取出里面的歌曲ID:
/************************************************************************/
// 函數(shù)名稱: AnalyseXUrl
// 參數(shù)列表:
// 1、 pUrl : 要分析的網(wǎng)址。
// 2、 desMusicID: 用來存放歌曲ID的緩沖區(qū)。
// 3、 desBufLen : URL中存在歌曲ID的數(shù)量。
// 函數(shù)功能:
// 從給定的網(wǎng)址中分離出歌曲的ID。
// 返回值 :
// 獲取成功返回TRUE, 否則是FALSE。
/************************************************************************/
BOOL WINAPI AnalyseXUrl(PCHAR pUrl, PDWORD desMusicID, PDWORD desBufLen)
{
bool bStart = false;
char tmpID[10] = {0};
int UrlLen = lstrlen(pUrl);
if (0 < UrlLen)
{
if (NULL != strstr(pUrl, "haoting.com/htmusic/\0") && NULL != strstr(pUrl, ".htm\0"))
{
//http://www.haoting.com/htmusic/357857ht.htm
for (int i = 0, x = 0; i<lstrlen(pUrl); i++)
{
if (pUrl[i] >= '0' && pUrl[i] <= '9')
{
tmpID[x] = pUrl[i];
x++;
}
}
sscanf(tmpID, "%d", desMusicID);
*desBufLen = 1;
return TRUE;
}
else if(NULL != strstr(pUrl, ".htm?id=\0"))
{
*desBufLen = 0;
//http://www.haoting.com/play/htsonglian1.htm?id=123907&id=357857
for (int i = 0, x = 0; i<lstrlen(pUrl); i++)
{
if (i>=0 && pUrl[i-1] == '=')
{
bStart = true;
x = 0;
}
if (pUrl[i] == '&')
{
bStart = false;
sscanf(tmpID, "%d", desMusicID);
*desBufLen += 1;
desMusicID++;
RtlZeroMemory(tmpID, 10);
}
if (bStart)
{
tmpID[x] = pUrl[i];
x++;
}
}
sscanf(tmpID, "%d", desMusicID);
*desBufLen += 1;
return TRUE;
}
else
{
return FALSE;
}
}
else
{
return FALSE;
}
}
OK,成功得到ID我們就可以構(gòu)造一個網(wǎng)址,得到ID對應(yīng)歌曲的信息:
/************************************************************************/
// 函數(shù)名稱: GetXCode
// 參數(shù)列表:
// 1、 nMusicID: 指定歌曲的ID
// 2、 desCode : 用來存放HTML代碼的緩沖區(qū)
// 函數(shù)功能:
// 獲取指定URL中的HTML代碼。
// 返回值 :
// 返回獲取的代碼的字節(jié)數(shù)。
/************************************************************************/
int WINAPI GetXCode(int nMusicID, PCHAR desCode)
{
char szMusicID[10] = {0};
BOOL bReadFlg = FALSE;
char MusicXCodeBuf[1024] = {0};
DWORD dwBytesRead = 0;
char pUrl[128] = "http://haoting.com/musicjs/\0"; //"http://haoting.com/musicjs/"+musicids[idindex]+".js"
sprintf(szMusicID, "%d", nMusicID);
lstrcat(pUrl, szMusicID);
lstrcat(pUrl, ".js\0");
HINTERNET hNet = ::InternetOpen("Wonderful Songs", //當(dāng)HTTP協(xié)議使用時,這個參數(shù)隨意賦值
PRE_CONFIG_INTERNET_ACCESS, //訪問類型指示W(wǎng)in32網(wǎng)絡(luò)函數(shù)使用登記信息去發(fā)現(xiàn)一個服務(wù)器。
NULL,
INTERNET_INVALID_PORT_NUMBER, //使用INTERNET_INVALID_PORT_NUMBER相當(dāng)于提供卻省的端口數(shù)。
0 //標志去指示使用返回句句柄的將來的Internet函數(shù)將"不"為回調(diào)函數(shù)發(fā)送狀態(tài)信息
) ;
HINTERNET hUrlFile = ::InternetOpenUrl(hNet, //從InternetOpen返回的句柄
pUrl, //需要打開的URL ,我們要打開哪個網(wǎng)址就可以填到這里
NULL, //用來向服務(wù)器傳送額外的信息,一般為NULL
0, //用來向服務(wù)器傳送額外的信息,一般為 0
INTERNET_FLAG_RELOAD, //InternetOpenUrl行為的標志
0) ; //信息將不會被送到狀態(tài)回調(diào)函數(shù)
bReadFlg = ::InternetReadFile(hUrlFile, //InternetOpenUrl返回的句柄
MusicXCodeBuf, //保留數(shù)據(jù)的緩沖區(qū),也就是存放網(wǎng)頁的內(nèi)容拉
sizeof(MusicXCodeBuf),
&dwBytesRead); //指向包含讀入緩沖區(qū)字節(jié)數(shù)的變量的指針;
if (!bReadFlg)
{
lstrcpy(desCode, "連接超時\0");
}
else
{
lstrcpy(desCode, MusicXCodeBuf);
}
::InternetCloseHandle(hUrlFile);
::InternetCloseHandle(hNet);
return lstrlen(desCode);
}
/************************************************************************/
// 函數(shù)名稱: AnalyseXCode
// 參數(shù)列表:
// 1、 nMusicID: 歌曲ID。
// 2、 XCode : HTML代碼。
// 函數(shù)功能:
// 從JS代碼中分離歌曲的關(guān)鍵信息到結(jié)構(gòu)體中。
// 返回值 :
// 返回 SONG_STRU 結(jié)構(gòu),其中存放的歌曲的信息。
// 參數(shù)的格式:
// var url_357857="/21z/0/dianxiao2yyyyqx090620/1/0897053676a18e5e_1.wma";
// var music_357857="相愛后動物感傷(CD Version) - 阿密特(張惠妹)";
// var singer_357857="最新單曲";
// var nclassid_357857=5538;
// var specialid_357857="abb60fe6d6c77f45";
// var specialName_357857="最新單曲合輯NO.48";
/************************************************************************/
SONG_STRU WINAPI AnalyseXCode(int nMusicID, PCHAR XCode)
{
bool bStart = false;
char *pdest;
char tmpStr[128] = {0};
char szMusicID[10] = {0};
SONG_STRU struMusicInfo ;
struMusicInfo.id = nMusicID;
struMusicInfo.MusicName = new char[128];
struMusicInfo.Singer = new char[128];
struMusicInfo.specialName = new char[128];
struMusicInfo.Url = new char[128];
if (XCode != NULL)
{
//解析下載地址
pdest = strstr(XCode, "url_\0");
if (NULL != pdest)
{
for (int i = pdest - XCode + 1, x = 0; i<lstrlen(XCode); i++)
{
if (i>=0 && XCode[i-2] == '=')
{
bStart = true;
x = 0;
}
if (XCode[i+1] == ';')
{
bStart = false;
if(strstr(tmpStr, "/19z/\0")==NULL && strstr(tmpStr, "/20z/\0")==NULL && \
strstr(tmpStr, "/21z/\0")==NULL && strstr(tmpStr, "/22z/\0")==NULL)
{
lstrcpy(struMusicInfo.Url, "http://ow.haoting.com");
}
else
{
lstrcpy(struMusicInfo.Url, "http://wma.haoting.com");
}
lstrcat(struMusicInfo.Url, tmpStr);
RtlZeroMemory(tmpStr, 128);
break;
}
if (bStart)
{
tmpStr[x] = XCode[i];
x++;
}
}
}
//解析歌曲名字
pdest = strstr(XCode, "music_\0");
if (NULL != pdest)
{
for (int i = pdest - XCode + 1, x = 0; i<lstrlen(XCode); i++)
{
if (i>=0 && XCode[i-2] == '=')
{
bStart = true;
x = 0;
}
if (XCode[i+1] == ';')
{
bStart = false;
lstrcpy(struMusicInfo.MusicName, tmpStr);
RtlZeroMemory(tmpStr, 128);
break;
}
if (bStart)
{
tmpStr[x] = XCode[i];
x++;
}
}
}
//解析歌手名字
pdest = strstr(XCode, "singer_\0");
if (NULL != pdest)
{
for (int i = pdest - XCode + 1, x = 0; i<lstrlen(XCode); i++)
{
if (i>=0 && XCode[i-2] == '=')
{
bStart = true;
x = 0;
}
if (XCode[i+1] == ';')
{
bStart = false;
lstrcpy(struMusicInfo.Singer, tmpStr);
RtlZeroMemory(tmpStr, 128);
break;
}
if (bStart)
{
tmpStr[x] = XCode[i];
x++;
}
}
}
//解析專輯名字
pdest = strstr(XCode, "specialName_\0");
if (NULL != pdest)
{
for (int i = pdest - XCode + 1, x = 0; i<lstrlen(XCode); i++)
{
if (i>=0 && XCode[i-2] == '=')
{
bStart = true;
x = 0;
}
if (XCode[i+1] == ';')
{
bStart = false;
lstrcpy(struMusicInfo.specialName, tmpStr);
RtlZeroMemory(tmpStr, 128);
break;
}
if (bStart)
{
tmpStr[x] = XCode[i];
x++;
}
}
}
}
return struMusicInfo;
}
然后將它得到的信息顯示到程序的界面的就可以了,由于直接顯示在分析的時候,會造成界面的暫時性假死,所以我單獨拋了個線程來完成分析的工作,界面只負責(zé)顯示,然后在分析的時候加上等待時間,以減少對網(wǎng)絡(luò)和電腦資源的消耗。
效果如下圖:

當(dāng)然,如果大家有興趣,可以寫個程序,通過對ID的遍歷來實現(xiàn)歌曲搜索、下載等功能,不過可能會比較消耗網(wǎng)絡(luò)資源我就不寫了,嘿嘿!
工程下載:
/Files/bester/HaotingPlg/GetDownloadUrlPlg.rar