安哥网络 发表于 2012-12-12 18:27:31

使用nginx反向代理获取百度MP3的真实网址

在没有自己的音乐搜索引擎的时候,却又想让用户可以较为方便的在自己的网站上搜索网络歌曲,在这里使用的是百度的MP3~
换成以前也许很简单,直接抓取网页就可以获取了网络音乐的实际URL。而现在不行了,搜索出来结果后,需要再次点击请求后台生成一个地址,然后那个页面才有真实MP3的URL地址。我使用的方法可能较为被动,如果百度MP3一些规则一旦改动,下面的代码就跑不起来了(在保持现在规则不变的情况下,看上去还是很完美的)
http://images.cnblogs.com/cnblogs_com/meteoric_cry/201101/20110110201006693.png

目前我做的是,只搜索第一页的音乐,如果你想实现与百度一致的翻页,可能还需要再花点时间了(不过应该会很简单了)

首先,我使用的开发环境:
操作系统:xp sp3
web服务器:nginx
flash开发IDE:flashDevelop
网页开发工具:Editplus

思路:
网页获取keyword -->传递给flash –> flash通过nginx反向代理请求百度mp3首页的网页内容 –> 回传给javascript

用户点击“试听”听 –> 将百度MP3首页的临时地址传给flash重新再请求一次(也采用nginx的反向代理) –> 获取最终真实地址的网页内容-->回传给javascript -->脚本通过解码函数再得真实的播放地址。

需要注意项:
1、百度的MP3请求地址,做了防盗链,在flash的http请求头里面需要设置host <ip地址>、清空referer、设置不缓存页面(每次重新请求),nginx代码大致如下:
proxy_set_header host '220.181.38.82';   
proxy_set_header referer '';
add_header Cache-Control 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0';
add_header Pragma no-cache;
proxy_pass http://220.181.38.82;
2、需要在服务器(本地)放置crossdomain.xml文件(因为flash的安全策略,请求资源时它会请求当前根目录下的crossdomain.xml文件,不符合规则将报安全沙箱错误)

下面测试一下,到底下面的方法得到的真实的URL是否正确:
http://images.cnblogs.com/cnblogs_com/meteoric_cry/201101/201101102010084955.png
http://images.cnblogs.com/cnblogs_com/meteoric_cry/201101/201101102010121461.png
注意它百度跳到指定的一个IP上,而不是域名,如果nginx里设置域名也是不行的,一定要用IP。

从两张图的对比来看,试验的页面是可以获得百度MP3的真实的网络地址, 项目测试成功。

nginx配置:#VHOST: meteoric.com
   server {
   listen 80;
   server_name meteoric.com

   charset utf-8;
   access_log off;

   ssi on;
   ssi_silent_errors on;

   location / {
       root C:\phpApp;      
       index index.html index.php;
   }

   location /crossdomain.xml {
       alias C:/phpApp/searchMusic/crossdomain.xml;
       }

   location ~ ^/baidu(/?) {
       rewrite .* http://www.baidu.com/ redirect;
   }

   location ~ ^/m$ {
       proxy_set_header host '220.181.43.121';
       proxy_set_header referer '';
       proxy_passhttp://mp3.baidu.com;
   }

   location ~ ^(.+\.php)(.*)$ {
       root C:\phpApp;
       fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
       include php.conf;
   }
    }

    #VHOST: meteoric2.com
    server {
   listen      80;
   server_name meteoric2.com;
   charset   utf-8;
   
   location /crossdomain.xml {
       alias C:/phpApp/searchMusic/crossdomain.xml;
   }
   location ~ ^/m$ {
       proxy_set_header host '220.181.38.82';
       proxy_set_header referer '';
       add_header Cache-Control 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0';
       add_header Pragma no-cache;
       proxy_pass http://220.181.38.82;
   }
   }解析百度MP3首页音乐列表脚本:if (/<div(?:\s+)id=\"songResults\"[^>]+\>[\n\s]*(<table[\S\s]*?\<\/table\>)/.test(_data)) {
            var table_str = RegExp['$1'];
            var tr_reg = /(<tr[^>]*>[\S\s]+?<\/tr>)/;
            var tr_str = "";

            musicList = [];

            while (tr_reg.test(table_str)) {
                tr_str = RegExp['$1'];
                table_str = table_str.replace(tr_str, "");

                if (/<td/.test(tr_str)) {
                  musicList.push({
                        'tmpurl' : /<td(?:\s+)class=\"second\">[^<]*<a(?:\s+)href=\"([^\"]+)/.test(tr_str) ? RegExp['$1'] : "",
                        'name' : /<td(?:\s+)class=\"second\">[^>]+>([^<]+)/.test(tr_str) ? RegExp['$1'] : "",
                        'singer' : /<td(?:\s+)class=\"third\">[^>]+>[^>]+>([^<]+)/.test(tr_str) ? RegExp['$1'] : "",
                        'relurl' : null,
                        'size' : /<td(?:\s+)class=\"seventh\">([^<]+)/.test(tr_str) ? RegExp['$1'] : "",
                        'speed' : /<td(?:\s+)class=\"ninth\">[^>]+>(\d)</.test(tr_str) ? RegExp['$1']*1+1 : ""
                  });            
                }
            }         
      }解析网络音乐真实URL的核心方法:parseMusicURL : function(data) {
      if(data) {
            /var encurl\s*=\s*\"([^\"]*)\"\s*\|\|\s+\"([^\"]*)\"/.test(data);
            
            var encurl = RegExp['$1'] || RegExp['$2'];
            
            /var song_(\d+)/.test(data);
            
            var sertim = RegExp['$1'];
            
             if(sertim && encurl) {
                return this.decodeMusicURL(sertim, encurl);
             } else {
                return null;
             }
            
      } else {
            return null;
      }
    },
    decodeMusicURL : function(_rId, _url) {
      var sertim = parseInt(_rId, 10);
      var url = _url;
         
      var len = url.length;
      var decurl = "";
      var asc_arr1 = [], asc_arr2 = [];

      var key = sertim % 26;
      key = key ? key : 1;

      function init(head, bottom, middle){
            for (var i = head; i <= bottom; i++) {
                asc_arr1 = i + middle;
                asc_arr2 = i;
            }
      }

      init(0, 9, 48);
      init(10, 35, 55);
      init(36, 61, 61);

      for (var i = 0; i < len; i++) {
            var word = url.charAt(i);

            if (//.test(word)) {
                var pos = asc_arr2 - key;
                if (pos < 0)
                  pos += 62;
                word = String.fromCharCode(asc_arr1);
            }
            decurl += word;
      }

      return decurl;   
    }代理请求的Flash代码:package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.external.ExternalInterface;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.net.URLRequestMethod;
    import flash.system.System;
   
    /**
   * ...
   * @author ZhangYi
   */
    public class Main extends Sprite
    {
         
      private static var CallBack_Fun:String;
         
      public function Main():void
      {
            if (stage) {
                init();
            } else {
                addEventListener(Event.ADDED_TO_STAGE, init);
            }
      }
         
      private function init(e:Event = null):void
      {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            
            inited();
      }
         
      private function inited():void {
            if (ExternalInterface.available) {
                ExternalInterface.addCallback("loadURL", loadURL);
            }
            
            System.useCodePage = true;
            var params:Object = root.loaderInfo.parameters;
            
            if (params.initCallback) {
                ExternalInterface.call(params.initCallback);
            }
      }
         
      /**
         * 请求指定的地址,获取数据后返回
         *
         * @param   _url
         * @param   _callback
         * @param   method
         */
      public function loadURL(_url:String, _callback:String = "", method:String = "get"):void {
            var req:URLRequest = new URLRequest(_url);
                req.method = method == "get" ? URLRequestMethod.GET : "POST";
            
            var loader:URLLoader = new URLLoader();
            
            loader.addEventListener(Event.COMPLETE, onCompleteHandler);
            loader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
            
            CallBack_Fun = _callback;
            
            loader.load(req);
      }
      /**
         * 数据加载完成
         * @param   evt
         */
      private function onCompleteHandler(evt:Event):void {
            var loader:URLLoader = evt.target as URLLoader;
            
            ExternalInterface.call(CallBack_Fun, loader.data);
      }
      /**
         * 请求时发生IO错误
         * @param   evt
         */
      private function ioErrorHandler(evt:IOErrorEvent):void {
            ExternalInterface.call(CallBack_Fun, null, evt.text);
      }
         
    }
   
}实际运行请求的效果示意图:
http://images.cnblogs.com/cnblogs_com/meteoric_cry/201101/201101102010214648.jpg

获取音乐列表的请求<也就是百度MP3首页的字符--网页源代码>:
http://images.cnblogs.com/cnblogs_com/meteoric_cry/201101/201101102010288382.png

请求网络音乐的真实URL时,网页内有一个javascript解码函数:
http://images.cnblogs.com/cnblogs_com/meteoric_cry/201101/201101102010329348.png

除nginx外,其它源码(html、css、flash)都将上传打包。不一定非得用nginx,你也可以使用apache,只是我的开发环境中经常用。
↓下载示例
本文转载自:http://www.cnblogs.com/meteoric_cry/archive/2011/01/10/1932312.html




页: [1]
查看完整版本: 使用nginx反向代理获取百度MP3的真实网址