首页
社区
课程
招聘
[原创]好听音乐网 -- 歌曲下载分析流程及程序的编写
发表于: 2009-6-25 22:06 16657

[原创]好听音乐网 -- 歌曲下载分析流程及程序的编写

2009-6-25 22:06
16657
难得我母亲要我给她下音乐听,她在好听音乐网上听到一首,我就要百度好久才能找到播放的是哪首,好长时间才下了仅仅的几首。
记得以前迅雷可以直接分析出下载地址来的,可是现在不知怎么的,迅雷的版本高了,功能却变得弱智了。
没有办法就只有自己找找规律分析一下了,下面记录我的分析过程,贴出来纪念下:

先看下网址的规律:
多个歌曲连播的URL地址形式:

http://www.haoting.com/play/htsonglian1.htm?id=123907&id=357857

其中id=后面的数字就是歌曲的ID。

单首歌曲播放的URL形式:
http://www.haoting.com/htmusic/357857ht.htm

其中的数字就是歌曲的ID。

查看其源文件,得到如下内容:
<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"; // 这个是关键。
  document.getElementsByTagName("head")[0].appendChild(s);
 
 }
 
}


由于到这里两种网址中歌曲的ID已经都取到了只要访问如下格式的URL:
http://haoting.com/musicjs/歌曲的ID.js

比如:
http://haoting.com/musicjs/357857.js


就可以下载到如下内容的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";     //这个是专辑名


我们知道这个音乐在网站上的相对地址了,怎么才能知道它完整的地址呢?

继续分析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 = "http://wma.haoting.com";
 haotingplay.url=ht+url;

再看下相对地址:
var url_357857="/21z/0/dianxiao2yyyyqx090620/1/0897053676a18e5e_1.wma";


根据上面的文件我们可以提取出很多的信息,其中下载地址如下:
http://wma.haoting.com/21z/0/dianxiao2yyyyqx090620/1/0897053676a18e5e_1.wma


分析完毕,下面开始写个小程序,让它自动完成我上面的分析过程并显示结果:
首先需要用程序来分解上面的网址,从中提取出里面的歌曲ID:
/************************************************************************/
// 函数名称:    AnalyseXUrl
// 参数列表:
//            1、 pUrl      : 要分析的网址。
//            2、    desMusicID:    用来存放歌曲ID的缓冲区。
//            3、 desBufLen :    URL中存在歌曲ID的数量。
// 函数功能:
//                从给定的网址中分离出歌曲的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我们就可以构造一个网址,得到ID对应歌曲的信息:
/************************************************************************/
// 函数名称:    GetXCode
// 参数列表:    
//            1、    nMusicID:    指定歌曲的ID
//            2、 desCode    :    用来存放HTML代码的缓冲区
// 函数功能:
//                获取指定URL中的HTML代码。
// 返回值  :
//            返回获取的代码的字节数。
/************************************************************************/
int WINAPI GetXCode(int nMusicID, PCHAR desCode)
{
    char    szMusicID[10] = {0};
    BOOL    bRead*** = 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", //当HTTP协议使用时,这个参数随意赋值 
        PRE_CONFIG_INTERNET_ACCESS, //访问类型指示Win32网络函数使用登记信息去发现一个服务器。 
        NULL, 
        INTERNET_INVALID_PORT_NUMBER, //使用INTERNET_INVALID_PORT_NUMBER相当于提供却省的端口数。 
        0 //标志去指示使用返回句句柄的将来的Internet函数将"不"为回调函数发送状态信息 
        ) ; 
    
    HINTERNET hUrlFile = ::InternetOpenUrl(hNet,    //从InternetOpen返回的句柄 
        pUrl,    //需要打开的URL ,我们要打开哪个网址就可以填到这里
        NULL,    //用来向服务器传送额外的信息,一般为NULL 
        0,        //用来向服务器传送额外的信息,一般为 0 
        INTERNET_FLAG_RELOAD, //InternetOpenUrl行为的标志 
        0) ;    //信息将不会被送到状态回调函数 

    bRead*** = ::InternetReadFile(hUrlFile,        //InternetOpenUrl返回的句柄 
            MusicXCodeBuf,            //保留数据的缓冲区,也就是存放网页的内容拉
            sizeof(MusicXCodeBuf), 
            &dwBytesRead);    //指向包含读入缓冲区字节数的变量的指针; 

    if (!bRead***)
    {
        lstrcpy(desCode, "连接超时\0");
    }
    else
    {
        lstrcpy(desCode, MusicXCodeBuf);
    }


    ::InternetCloseHandle(hUrlFile); 
    ::InternetCloseHandle(hNet); 

    return lstrlen(desCode);
}

/************************************************************************/
// 函数名称:    AnalyseXCode
// 参数列表:    
//            1、 nMusicID:    歌曲ID。
//            2、    XCode     :    HTML代码。
// 函数功能:
//                从JS代码中分离歌曲的关键信息到结构体中。
// 返回值  :
//                返回 SONG_STRU 结构,其中存放的歌曲的信息。
// 参数的格式:
//                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;
}

        然后将它得到的信息显示到程序的界面的就可以了,由于直接显示在分析的时候,会造成界面的暂时性假死,所以我单独抛了个线程来完成分析的工作,界面只负责显示,然后在分析的时候加上等待时间,以减少对网络和电脑资源的消耗。
         效果如下图:


当然,如果大家有兴趣,可以写个程序,通过对ID的遍历来实现歌曲搜索、下载等功能,不过可能会比较消耗网络资源我就不写了,嘿嘿!

[课程]Linux pwn 探索篇!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (27)
雪    币: 168
活跃值: (152)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
2
第一次发主题,很激动,今天刚分析写的程序就第一时间发出来了,程序和文章中肯定有很多的问题,希望大家多多指教……
刚学编程,所以文章没什么技术含量,程序中肯定也有很多有待提高的地方,让大家见笑了。
嘿嘿~~~
2009-6-25 22:07
0
雪    币: 210
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
精神上支持一下!
2009-6-25 22:17
0
雪    币: 1450
活跃值: (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
4
下了看看~
好久没看到javascript了~
2009-6-25 22:40
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
5
很不错。支持~
2009-6-25 22:41
0
雪    币: 250
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
Thx a lot  to share it.
2009-6-26 09:11
0
雪    币: 220
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
先赞一个
我是来拿EXE 的
实话说,这是一个取巧的方法,对网址过于依赖了,短期内大量下载是没有问题的,被官方发现了就不行了。。

刚刚才发现线程创建以后就不能手工把它暂停了,太水了。。
2009-6-26 09:56
0
雪    币: 430
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
感谢楼主的分享,代码手下,学到了东西~~
2009-6-26 10:13
0
雪    币: 281
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
个人觉得这样的工作perl 或者 python 或者更适合!

不过还是感谢下楼主 ..
2009-6-26 14:08
0
雪    币: 370
活跃值: (52)
能力值: ( LV13,RANK:350 )
在线值:
发帖
回帖
粉丝
10
学习了 有始有终 顶
2009-6-26 17:11
0
雪    币: 372
活跃值: (36)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
11
分析得很好收获很多呵呵
2009-6-28 08:22
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
其实haoting网站的歌曲是用Midea Player播放的,在IE的临时文件夹(IE的Tools->Internet 选项->常规->浏览历史记录->设置->查看文件,这样可以打开临时文件夹)下是可以找到相应的wma文件。你只要将其拷贝出来就够了。当然不能识别临时文件的文件名,临时文件都是以网址的名字命名的,所以拷贝多个文件的时候可能会重名。但是自己写个小程序就可以批量拷贝并重命名了。
2009-6-28 21:41
0
雪    币: 284
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
我说最近bester怎么没消息了,原来在这里研究音乐呢啊。顶1··
2009-6-28 22:42
0
雪    币: 100
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
下载后试用一下,我也经常去这个网站听音乐去。
2009-6-30 15:52
0
雪    币: 284
活跃值: (106)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
15
恩,很值得借鉴的思路^
2009-6-30 18:39
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
16
不错,很支持!
2009-6-30 18:49
0
雪    币: 101
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
见识了,不是很懂
2009-6-30 19:06
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
学以致用 不错!学习了
2009-6-30 21:39
0
雪    币: 411
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
谢谢LZ,支持原创。
2009-7-1 10:42
0
雪    币: 113
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
不错,借鉴一下
2009-7-1 13:44
0
雪    币: 433
活跃值: (1875)
能力值: ( LV17,RANK:1820 )
在线值:
发帖
回帖
粉丝
21
不错,好东西,支持并学习一下!
2009-11-25 12:00
0
雪    币: 230
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
22
我觉得楼主很有潜质。。能把知识应用起来,,这在以后工作中非常重要。。
2009-11-25 21:33
0
雪    币: 219
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
好文章 感谢大哥
2009-11-25 22:23
0
雪    币: 351
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
mark..
2009-11-25 23:10
0
雪    币: 225
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
好文章!支持楼主
2009-11-25 23:41
0
游客
登录 | 注册 方可回帖
返回
//