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


    在没有自己的音乐搜索引擎的时候,却又想让用户可以较为方便的在自己的网站上搜索网络歌曲,在这里使用的是百度的MP3~

    换成以前也许很简单,直接抓取网页就可以获取了网络音乐的实际URL。而现在不行了,搜索出来结果后,需要再次点击请求后台生成一个地址,然后那个页面才有真实MP3的URL地址。我使用的方法可能较为被动,如果百度MP3一些规则一旦改动,下面的代码就跑不起来了(在保持现在规则不变的情况下,看上去还是很完美的)

    image

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

    首先,我使用的开发环境:

    操作系统: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是否正确:

    image

    image

    注意它百度跳到指定的一个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_pass  http://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] = i + middle;
                    asc_arr2[i + middle] = 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 (/[A-Za-z0-9]/.test(word)) {
                    var pos = asc_arr2[url.charCodeAt(i)] - key;
                    if (pos < 0)
                        pos += 62;
                    word = String.fromCharCode(asc_arr1[pos]);
                }
                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);
    		}
    		
    	}
    	
    }

    实际运行请求的效果示意图:

    3B2CFG18{P@0JPT%`G_BQ8U

    获取音乐列表的请求<也就是百度MP3首页的字符--网页源代码>:

    image

    请求网络音乐的真实URL时,网页内有一个javascript解码函数:

    image

    除nginx外,其它源码(html、css、flash)都将上传打包。不一定非得用nginx,你也可以使用apache,只是我的开发环境中经常用。

    ↓下载示例

  • 相关阅读:
    iPhone开发指南应用程序核心
    id,SEL,Nil,nil,IMP,Method,Class类型
    需求驱动赢得创新
    Linux内核list&hlist解读
    转载:x86的cpu_relax解析
    hadoop开发者第三期
    Hadoop开发者入门专刊
    Hadoop源代码eclipse编译指南
    高效的使用stl::map和std::set
    配置VIM语法高亮及自动缩进
  • 原文地址:https://www.cnblogs.com/meteoric_cry/p/1932312.html
Copyright © 2020-2023  润新知