利用百度mp3的搜索结果下载网络音乐

以前看到过网友写的“百度Mp3批量下载程序”,现在自己也研究下一。首先上http://mp3.baidu.com/搜索几首歌,看看百度网站生成动态页面地址的方式。发现它是有规律的,以下是我的记录:

搜索七里香,所有格式
http://mp3.baidu.com/m?f=ms&tn=baidump3&ct=134217728&lf=&rn=&word=%C6%DF%C0%EF%CF%E3&lm=-1 第一页
http://mp3.baidu.com/m?z=0&cl=3&ct=134217728&sn=&lm=-1&cm=1&sc=1&bu=&rn=30&tn=baidump3&word=%C6%DF%C0%EF%CF%E3&pn=30 第二页
http://mp3.baidu.com/m?z=0&cl=3&ct=134217728&sn=&lm=-1&cm=1&sc=1&bu=&rn=30&tn=baidump3&word=%C6%DF%C0%EF%CF%E3&pn=60 第三页
http://mp3.baidu.com/m?z=0&cl=3&ct=134217728&sn=&lm=-1&cm=1&sc=1&bu=&rn=30&tn=baidump3&word=%C6%DF%C0%EF%CF%E3&pn=90 第四页
http://mp3.baidu.com/m?z=0&cl=3&ct=134217728&sn=&lm=-1&cm=1&sc=1&bu=&rn=30&tn=baidump3&word=%C6%DF%C0%EF%CF%E3&pn=720 最后页 30首


搜索七里香,mp3格式
http://mp3.baidu.com/m?f=ms&tn=baidump3&ct=134217728&lf=&rn=&word=%C6%DF%C0%EF%CF%E3&lm=0 第一页
http://mp3.baidu.com/m?z=0&cl=3&ct=134217728&sn=&lm=0&cm=1&sc=1&bu=&rn=30&tn=baidump3&word=%C6%DF%C0%EF%CF%E3&pn=30 第二页
http://mp3.baidu.com/m?z=0&cl=3&ct=134217728&sn=&lm=0&cm=1&sc=1&bu=&rn=30&tn=baidump3&word=%C6%DF%C0%EF%CF%E3&pn=630 最后页7首

搜索七里香,rm格式
http://mp3.baidu.com/m?f=ms&tn=baidump3&ct=134217728&lf=&rn=&word=%C6%DF%C0%EF%CF%E3&lm=1 第一页
http://mp3.baidu.com/m?z=0&cl=3&ct=134217728&sn=&lm=1&cm=1&sc=1&bu=&rn=30&tn=baidump3&word=%C6%DF%C0%EF%CF%E3&pn=30 最后页,17首

搜索七里香,wma格式
http://mp3.baidu.com/m?f=ms&tn=baidump3&ct=134217728&lf=&rn=&word=%C6%DF%C0%EF%CF%E3&lm=2 第一页
http://mp3.baidu.com/m?z=0&cl=3&ct=134217728&sn=&lm=2&cm=1&sc=1&bu=&rn=30&tn=baidump3&word=%C6%DF%C0%EF%CF%E3&pn=30 第二页
http://mp3.baidu.com/m?z=0&cl=3&ct=134217728&sn=&lm=2&cm=1&sc=1&bu=&rn=30&tn=baidump3&word=%C6%DF%C0%EF%CF%E3&pn=240 最后页 13首

搜索七里香,其它格式
http://mp3.baidu.com/m?f=ms&tn=baidump3&ct=134217728&lf=&rn=&word=%C6%DF%C0%EF%CF%E3&lm=32767 第一页
http://mp3.baidu.com/m?z=0&cl=3&ct=134217728&sn=&lm=32767&cm=1&sc=1&bu=&rn=30&tn=baidump3&word=%C6%DF%C0%EF%CF%E3&pn=30 第二页
http://mp3.baidu.com/m?z=0&cl=3&ct=134217728&sn=&lm=32767&cm=1&sc=1&bu=&rn=30&tn=baidump3&word=%C6%DF%C0%EF%CF%E3&pn=240 最后页 4首

上面的链接中,“%C6%DF%C0%EF%CF%E3”是中文“七里香”的6个字节的十六进制编码,可以用“七里香”代替。稍微观察一下就可以发现,“http://mp3.baidu.com/m?f=ms&tn=baidump3&ct=134217728&lf=&rn=&word=歌曲名&lm=格式”就是搜索歌曲第一个结果页面URL,格式有-1(所有格式),0(mp3格式),1(rm格式),2(wma格式),32767(其它格式)5种。我没有把歌词搜索,视频搜索,铃声搜索包括在内,他们跟歌曲搜索的差异太大了。“http://mp3.baidu.com/m?z=0&cl=3&ct=134217728&sn=&lm=格式&cm=1&sc=1&bu=&rn=30&tn=baidump3&word=歌曲名&pn=起始数量N”是搜索第N/30+1页,格式意义同搜索第一页的情况。
   对照网页查看一下其源码,可以发现搜索结果页面中的每首歌曲是这样的形式的存在的

<tr>
<td class=tdn>1</td>
<td class=d><a href="http://202.108.23.172/m?ct=134217728&tn=baidusg,借口 &word=mp3,http://ddos.8833168.cn/wmp3/周杰伦/7hryDjU$.mp3,,[%C6%DF%C0%EF%CF%E3]&si=%BD%E8%BF%DA;;%D6%DC%BD%DC%C2%D7;;3708;;3708&lm=16777216" title="请点击左键!来源网址: http://ddos.8833168.cn/   请参照百度权利声明使用" onclick="return ow(event,this)" target="_blank">借口 </a></td>
<td><a href="http://mp3.baidu.com/singerlist/%D6%DC%BD%DC%C2%D7.html" target="_blank">周杰伦</a>&nbsp;<a href="http://mp3.baidu.com/singerlist/.html" target="_blank"></a>&nbsp;<a href="http://mp3.baidu.com/singerlist/.html" target="_blank"></a>&nbsp;</td>
<td class=al><a href="http://mp3.baidu.com/albumlist/%D6%DC%BD%DC%C2%D7;;;;;;%C6%DF%C0%EF%CF%E3.html" target="_blank"><font style=color:#e10900>七里香</font></a>&nbsp;</td>
<td><a href="http://box.zhangmen.baidu.com/m?gate=1&ct=134217728&tn=baidumt,借口 &word=mp3,http://ddos.8833168.cn/wmp3/周杰伦/7hryDjU$.mp3,,[%C6%DF%C0%EF%CF%E3]&si=%BD%E8%BF%DA;;%D6%DC%BD%DC%C2%D7;;3708;;3708&lm=16777216" onclick="return ot(event,this,'3708')">试听</a>&nbsp;</td>
<td><a href="http://mp3.baidu.com/m?tn=baidump3lyric&word=%D6%DC%BD%DC%C2%D7+%BD%E8%BF%DA&ct=150994944&lm=-1&lf=3" target="_blank">歌词</a>&nbsp;</td>
<td> <a name="ls" href="http://mp3.baidu.com/tr?url=http://ad.cn.doubleclick.net/clk;140266405;20620248;r?http://www.12530.com/main/all/subscribe/index/0/qd001/bd0092/1/0/0/null/--------------------------------------2560.html&sn=1" onclick="return or(event,this);">铃声</a>&nbsp;</td>
<td>3.9 M</td>
<td>mp3</td>
<td class=spd><img src="http://img.baidu.com/img/mp3/d9.gif%22%3E%3C/td>
</tr>

以下是分析结果:
   
    “<td class=tdn>1</td>”:歌曲的序号,每个下载页都不一样的,从1开始递增。我们分析页面中的歌曲就靠这个字符串了。利用一个循环读出所有歌曲下载页,知道查找“<td class=tdn>N</td>”不到为止。
    “http://202.108.23.172/m?ct=134217728&tn=baidusg,借口 &word=mp3,http://ddos.8833168.cn/wmp3/周杰伦/7hryDjU$.mp3,,[%C6%DF%C0%EF%CF%E3]&si=%BD%E8%BF%DA;;%D6%DC%BD%DC%C2%D7;;3708;;3708&lm=16777216”:这个URL就是带下载链接的页面。
   “target="_blank">借口 </a”:“借口”是歌曲的名字,有时搜索结果会有误,比如我搜索“七里香”就出来“借口”,可能是把“七里香”当专辑名了吧,而“借口”是这张专辑的一首歌。所以可以通过检查这里来确定是否下载。
   “<td>3.9 M</td>”:音乐文件的尺寸,一般来说wma有2M以上,Mp3为4M左右。太小的话歌曲不完整。
     “ <td>mp3</td>”:歌曲的类型。

打开http://202.108.23.172/m?ct=134217728&tn=baidusg,借口 &word=mp3,http://ddos.8833168.cn/wmp3/周杰伦/7hryDjU$.mp3,,[%C6%DF%C0%EF%CF%E3]&si=%BD%E8%BF%DA;;%D6%DC%BD%DC%C2%D7;;3708;;3708&lm=16777216这个页面,查看其源码看到:

<div style="padding:30px 0px 0px 40px;">
歌曲名:<a href="http://ddos.8833168.cn/wmp3/周杰伦/借口.mp3">借口   ...</a><br>
<li class="li" style="margin-top:2px;">请点击此链接:</li>

   傻瓜都知道了“http://ddos.8833168.cn/wmp3/周杰伦/借口.mp3”就是下载地址。左边的“歌曲名”和右边的“请点击此链接”是识别它的最明显方式。

了解这些后,不打开浏览器搜索歌曲就容易做了,只要你懂得如何在自己的程序中获取web页面源码。获取页面源码可以用WebBrowser,也可以用速度更快更轻巧的IdHttp组件(Indy套件的一个成员)。使用TIdHttp获取页面的方法是:

   src:=IdHttpObj.Get('www.163.com');


获取页面之后就是利用分析所得到的特征字符串来查找下载链接了。我很笨,不会列举页面的超链接啊,图片啊,表格啊,按钮啊什么的。我采用的是最原始的办法:字符串处理函数。Pos和Copy就够用了。

下面是我的代码,由于是练习玩。写得很不严谨哈。而且没有注释(我认为上面讲得已经很清楚了)。唯一需要说的是,http://202.108.23.172/m?ct=134217728&tn=baidusg,借口 &word=mp3,http://ddos.8833168.cn/wmp3/周杰伦/7hryDjU$.mp3,,[%C6%DF%C0%EF%CF%E3]&si=%BD%E8%BF%DA;;%D6%DC%BD%DC%C2%D7;;3708;;3708&lm=16777216这种URL中含有2个ASCII码为32的控制字符。这两个字符在“&word=”的前面,我们要把它们换成%20(就是32的十六进制码),否则用IdHttp是抓不到页面的。我只是做了最简单抓下载链接的功能。

unit FrmMainUnt;

interface

uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, StdCtrls, ExtCtrls, ComCtrls, FileDownLoadThread, UrlMon, IdBaseComponent,
    IdComponent, IdTCPConnection, IdTCPClient,
    IdHTTP,StrUtils;

type
    TMusicType 
= (mtAll=-1,mtMp3=0,mtRm=1,mtWma=2,mtOther=32767);
    TMusicInfo 
= record
        Name:string;
        DownUrl:string;
        Size: Real;
    
end;

    TFrmMain 
= class( TForm )
        ProgBar: TProgressBar;
        edtFileURL: TLabeledEdit;
        edtFilePath: TLabeledEdit;
        Label1: TLabel;
        btnStart: TButton;
        btnCancel: TButton;
        edtMusicName: TLabeledEdit;
        btnSearch: TButton;
        rgType: TRadioGroup;
        IdHTTP: TIdHTTP;
    lstResult: TListBox;
        
procedure FormCreate( Sender: TObject );
        
procedure btnStartClick( Sender: TObject );
        
procedure DownProgress( Sender: TFileDownLoadThread; Progress, ProgressMax: Cardinal );
        
procedure DownComplete( Sender: TFileDownLoadThread );
        
procedure DownFail( Sender: TFileDownLoadThread; Reason: LongInt );
        
procedure btnCancelClick( Sender: TObject );
        
procedure FormDestroy( Sender: TObject );
        
procedure btnSearchClick( Sender: TObject );
        
function SearchMusic(mName:string;mType:TMusicType):string;
        
procedure GetMusic(ResultUrl:string);
        
procedure lstResultClick(Sender: TObject);
    private
        FSearchResult:string;
    public
    
{ Public declarations }
    
end;

var
    FrmMain: TFrmMain;
    AThread: TFileDownLoadThread;

implementation

{$R *.dfm}

const
    ModelURL 
='http://mp3.baidu.com/m?f=ms&rn=&tn=baidump3&ct=134217728&word=%s&lm=%d';

procedure TFrmMain.btnCancelClick( Sender: TObject );
begin
    
if AThread <> nil then
    
begin
        AThread.Terminate;
        AThread.WaitFor;
        FreeAndNil( AThread );
    
end;
end;

procedure TFrmMain.btnSearchClick( Sender: TObject );
var
    MusicType:TMusicType;
begin
    
if rgType.ItemIndex<4 then
        MusicType:
=TMusicType(rgType.ItemIndex-1)
    
else
        MusicType:
=mtOther;
    try
        FSearchResult:
=SearchMusic(edtMusicName.Text,MusicType);
        GetMusic(FSearchResult);
    except
        FSearchResult:
='';
        ShowMessage(
'search failed');
    
end;
end;

procedure TFrmMain.btnStartClick( Sender: TObject );
var
    SaveFileName: string;
begin
    
if AThread = nil then
        AThread :
= TFileDownLoadThread.Create( edtFileURL.Text, edtFilePath.Text, DownProgress, DownComplete, DownFail );
end;

procedure TFrmMain.DownComplete( Sender: TFileDownLoadThread );
begin
    ShowMessage( 
'下载完成' );
end;

procedure TFrmMain.DownFail( Sender: TFileDownLoadThread; Reason: Integer );
begin
    OutputDebugString( PAnsiChar( Format( 
'Down Fail,Reason:%s', [ IntToHex( Reason, 8 ) ] ) ) );
end;

procedure UpdateProgressBar( Progress, Max: Cardinal );
begin
    
if Max > 0 then
        FrmMain.ProgBar.Position :
= ( Progress * FrmMain.ProgBar.Max ) div Max;
end;

procedure TFrmMain.DownProgress( Sender: TFileDownLoadThread; Progress, ProgressMax: Cardinal );
begin
    UpdateProgressBar( Progress, ProgressMax );
end;

procedure TFrmMain.FormCreate( Sender: TObject );
begin
    AThread :
= nil;
    rgType.ItemIndex:
=-1;
end;

procedure TFrmMain.FormDestroy( Sender: TObject );
begin
    btnCancelClick( 
nil );
end;

function GetMusicDownLoadURL(ADownPage:string):string;
const
    str 
= '歌曲名:<a href="';
var
    I,J:Integer;
begin
    I:
=Pos(str,ADownPage);
    J:
=PosEx('">',ADownPage,I+Length(str));
    Result:
=Copy(ADownPage,I+Length(str),J-I-Length(Str));
end;

procedure TFrmMain.GetMusic(ResultUrl: string);
const
    CharStr 
= '<td class=tdn>%d</td>' ;
    CharStr2 
= 'href="';
    CharStr3 
= 'title="请点击左键!来源网址';
var
    L,I,J:Integer;
    DownPage:string;
    FirstPart,SecondPart:string;
begin
    lstResult.Clear;
    L:
=1;
    
while True do
    
begin
        I:
=Pos( Format(CharStr,[L]),ResultUrl);
        
if I<=0 then Break;
        I:
=I+Length(CharStr);
        I:
=PosEx(CharStr2,ResultUrl,I)+Length(CharStr2);
        J:
=PosEx(CharStr3,ResultUrl,I);
        DownPage:
=Trim(Copy(ResultUrl,I,J-I));
        SetLength(DownPage,Length(DownPage)
-1);
        I:
=Pos('&word=',DownPage);
        FirstPart:
=Copy(DownPage,1,I-3);
        SecondPart:
=Copy(DownPage,I,Length(DownPage)-I+1);
        DownPage:
=FirstPart+'%20%20'+SecondPart;
        try
            lstResult.Items.Add(GetMusicDownLoadURL(Self.IdHTTP.Get(DownPage)));
        except
        
end;
        Inc(L);
    
end;
    
if lstResult.Count=0 then
        ShowMessage(
'没有找到歌曲!');
end;

procedure TFrmMain.lstResultClick(Sender: TObject);
begin
    
if lstResult.ItemIndex<>-1 then
        edtFileURL.Text:
=lstResult.Items[lstResult.ItemIndex];
end;

function TFrmMain.SearchMusic(mName: string; mType: TMusicType): string;
var
    AUrl:string;
begin
   AUrl:
=Format(ModelURL,[mName,Ord(mType)]);
   Result:
=Self.IdHTTP.Get(AUrl);
end;

end.
posted @ 2008-04-25 19:34  地质灾害  阅读(973)  评论(2编辑  收藏  举报