解析搜狗音乐的音乐下载地址

Object-c代码  收藏代码
  1. //  
  2. //  SougouMusicParser.h  
  3. //  
  4. //  Created by scott.8an@gmail.com on 12-3-13.  
  5. //  Copyright (c) 2012年 littleworn llc. All rights reserved.  
  6. //  
  7.   
  8. #import <Foundation/Foundation.h>  
  9. #import "ASIHTTPRequest.h"  
  10. #import "ASINetworkQueue.h"  
  11. #import "TFHpple.h"  
  12. #import "XPathQuery.h"  
  13. #import "TFHppleElement.h"  
  14. #import "DataType.h"  
  15.   
  16. //页面地址  
  17. #define kRequestURL(s_songName,i_pageNumber) \  
  18.         [NSString stringWithFormat:@"http://mp3.sogou.com/music.so?pf=mp3&query=%@&page=%i&w=02009900&dr=1",s_songName,i_pageNumber]  
  19.   
  20. @interface SogouMusicParser : NSObject  
  21.   
  22. + (SogouMusicParser*)shareInstance;  
  23.   
  24. /**  
  25.  发送成功通知的数组结构:  
  26.  [  
  27.     {  
  28.         "song"="save me",  
  29.         "artist"="Queen",  
  30.         "size"="4.38M",  
  31.         "firstChoose_url"="http://ziyuan1.myi.cn/film/YINYUE/fir/firT1563.mp3",  
  32.         "other_link"= [  
  33.             "http://mul1.tximg.cn/music/group/bbs/mp3/7/090528/1243462409315.mp3",  
  34.             "http://api.ning.com/files/SRIkTa2lzwqL1jt26257Yzj3TCFZ6jAJD2HaYhYB*N469JhRrd01xDttiHqjJD7K9WkWr69u6LnXChFfA2Wid0jWUfiIB33m/f.i.r._.mp3"  
  35.         ]  
  36.     },...  
  37.  ]  
  38.  **/  
  39. - (void)runToGetSongInfoFromSogouWithKeyword:(NSString*)kw pageNumber:(NSInteger)pgNum;  
  40. @end  



Object-c代码  收藏代码
  1. //  
  2. //  SougouMusicParser.m  
  3. //  
  4. //  Created by scott.8an@gmail.com on 12-3-13.  
  5. //  Copyright (c) 2012年 littleworn llc. All rights reserved.  
  6. //  
  7.   
  8. #import "SogouMusicParser.h"  
  9.   
  10. NSString *const SogouMusicParseSuccessNotification = @"SogouMusicParseSuccessNotification";  
  11. NSString *const SogouMusicParseFailedNotification = @"SogouMusicParseFailedNotification";  
  12.   
  13. static SogouMusicParser *parser_ = nil;  
  14.   
  15. @interface SogouMusicParser (Private)  
  16. //获得跳转地址的urls  
  17. /**  
  18.  [  
  19.  "http://mp3.sogou.com/down.so?gid=11950F9C68D7EDE7&globalId=1f940cf0056326c8&query=%CE%D2%C",  
  20.  "http://mp3.sogou.com/down.so?gid=11950F9C68D7EDE7&globalId=1f940cf0056326c8&query=%CE%D2%C",  
  21.  ...  
  22.  ]  
  23.  **/  
  24. - (NSArray*)getJumpToDownloadPageURLsWithKeyword:(NSString*)kw pageNumber:(int)pgNum;  
  25.   
  26. /**  
  27.  返回字典结构:  
  28.  {  
  29.  "song"="save me",  
  30.  "artist"="Queen",  
  31.  "size"="4.38M",  
  32.  "firstChoose_url"="http://ziyuan1.myi.cn/film/YINYUE/fir/firT1563.mp3",  
  33.  "other_link"= [  
  34.  "http://mul1.tximg.cn/music/group/bbs/mp3/7/090528/1243462409315.mp3",  
  35.  "http://api.ning.com/files/SRIkTa2lzwqL1jt26257Yzj3TCFZ6jAJD2HaYhYB*N469JhRrd01xDttiHqjJD7K9WkWr69u6LnXChFfA2Wid0jWUfiIB33m/f.i.r._.mp3"  
  36.  ]  
  37.  }  
  38.  **/  
  39. - (NSDictionary*)getMusicInfoByJumpToUrl:(NSString*)jumpToUrl;  
  40. @end  
  41.   
  42.   
  43. @implementation SogouMusicParser  
  44.   
  45. + (SogouMusicParser*)shareInstance{  
  46.     if (!parser_) {  
  47.         parser_ = [[self alloc] init];  
  48.     }  
  49.     return parser_;  
  50. }  
  51.   
  52. - (NSArray*)getJumpToDownloadPageURLsWithKeyword:(NSString*)kw pageNumber:(int)pgNum{  
  53.     if (kw && [kw length]) {  
  54.         //初始化需要返回的数组  
  55.         NSMutableArray *urlsArr = [NSMutableArray arrayWithCapacity:0];  
  56.           
  57.         //去掉搜索条件两端空格  
  58.         NSString *pureKW = [kw stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];  
  59.           
  60.         //用 + 号连接需要要搜索的绑定条件  
  61.         NSArray *kwArr = [pureKW componentsSeparatedByString:@" "];  
  62.         NSMutableString *neededKw = [NSMutableString stringWithCapacity:0];  
  63.         if (kwArr && [kwArr count]) {  
  64.             for (NSString *str in kwArr) {  
  65.                 [neededKw appendFormat:@"%@+",str];  
  66.             }  
  67.               
  68.             //去掉最后一个 + 号  
  69.             [neededKw deleteCharactersInRange:NSMakeRange([neededKw length]-11)];  
  70.         }else{  
  71.             neededKw = (NSMutableString*)kw;  
  72.         }  
  73.         //对url编码  
  74.         NSString *requestURLStr = kRequestURL(neededKw,pgNum);  
  75.         NSString *requestURLStrEnc = [requestURLStr stringByAddingPercentEscapesUsingEncoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000)];  
  76.       
  77.         //请求页面地址  
  78.         ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:requestURLStrEnc]];  
  79.         [request startSynchronous];  
  80.           
  81.         //获得返回数据  
  82.         //NSString *responseStr = [request responseString];  
  83.         NSData  *responseData = [request responseData];  
  84.         //NSLog(@"%@",responseStr);  
  85.           
  86.         if (responseData) {  
  87.             TFHpple *help = [TFHpple hppleWithHTMLData:responseData];  
  88.             if (help) {  
  89.                 //用xpath解析获得歌曲的跳转地址  
  90.                 //获得tbody节点  
  91.                 NSString *xPath = @"//*[@id='songlist']";  
  92.                 TFHppleElement *tableNode = [help peekAtSearchWithXPathQuery:xPath];  
  93.                 TFHppleElement *tBodyNode = tableNode.firstChild;  
  94.                 if (tBodyNode) {  
  95.                     NSMutableArray *childrenNodes = (NSMutableArray*)tBodyNode.children;  
  96.                     if (childrenNodes && [childrenNodes count]) {  
  97.                         //移除第一个node  
  98.                         [childrenNodes removeObjectAtIndex:0];  
  99.                         for (TFHppleElement *element in childrenNodes) {  
  100.                             NSArray *tdNodeArr = element.children;  
  101.                             if (tdNodeArr && [tdNodeArr count]) {  
  102.                                 for (TFHppleElement *tdEle in tdNodeArr) {  
  103.                                     TFHppleElement *aNode = tdEle.firstChild;  
  104.                                     if (aNode && [[aNode objectForKey:@"action"] isEqualToString:@"down"]) {  
  105.                                         /**  
  106.                                          window.open('/down.so?gid=1A6F5F0BA3CDD9C8&globalId=137c9db3dc0bf7bf&query=%B2%BB%C3%F0%B5%C4%B0%AE&tgid=629801e642a2eadc&pf=mp3&s=%CC%B7%D3%BD%F7%EB&t=%B2%BB%C3%F0%B5%C4%B0%AE&size=4195343&ac=0&c','  
  107.                                          ','width=431,height=495,scrollbars=no');  
  108.                                          uigsPB('consume=music_down&music_down=28');return(false);  
  109.                                          */  
  110.                                         NSString *urlThatMixed = [aNode objectForKey:@"onclick"];  
  111.                                         NSArray *urlParts = [urlThatMixed componentsSeparatedByString:@"'"];  
  112.                                         //取第二个作为uri  
  113.                                         NSString *uri = [urlParts objectAtIndex:1];  
  114.                                           
  115.                                         if (uri && [uri length]) {  
  116.                                             NSString *url = [NSString stringWithFormat:@"http://mp3.sogou.com%@",uri];  
  117.                                             //NSLog(@"组合新的跳转地址:http://mp3.sogou.com%@",uri);  
  118.                                               
  119.                                             [urlsArr addObject:url];  
  120.                                         }  
  121.                                     }  
  122.                                 }  
  123.                             }  
  124.                         }  
  125.                         if ([urlsArr count]) {  
  126.                             return urlsArr;  
  127.                         }  
  128.                     }  
  129.                 }  
  130.             }  
  131.         }else{  
  132.             //再次尝试  
  133.             [self getJumpToDownloadPageURLsWithKeyword:kw pageNumber:pgNum];  
  134.         }  
  135.     }  
  136.     return nil;  
  137. }  
  138.   
  139. - (NSDictionary*)getMusicInfoByJumpToUrl:(NSString*)jumpToUrl{  
  140.     if (jumpToUrl && [jumpToUrl length]) {  
  141.         //获得下载页面,不需要编码,因为获得的数据已经是编码过了的  
  142.         ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:jumpToUrl]];  
  143.         [request startSynchronous];  
  144.           
  145.         //获得返回界面  
  146.         NSString *responseStr = [request responseString];  
  147.         NSData *responseData = [request responseData];  
  148.       // NSLog(@"返回下载界面的网页信息:%@",responseStr);  
  149.           
  150.         if (responseData) {  
  151.             NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:0];  
  152.               
  153.             //解析页面  
  154.             TFHpple *help = [TFHpple hppleWithHTMLData:responseData];  
  155.               
  156.             /**  
  157.              1.查找歌曲的下载地址  
  158.              **/  
  159.               
  160.             //href="..+.mp3"  
  161.             NSString *pattern = @"href=\"..+.mp3\"";  
  162.             NSRegularExpression *exp = [NSRegularExpression regularExpressionWithPattern:pattern  
  163.                                                                                  options:NSRegularExpressionCaseInsensitive  
  164.                                                                                    error:nil];  
  165.             NSArray *metchedArr = [exp matchesInString:responseStr options:NSMatchingReportProgress range:NSMakeRange(0, [responseStr length])];  
  166.           
  167.             if (metchedArr && [metchedArr count]) {  
  168.                 //用数组保存其他连接  
  169.                 NSMutableArray *otherLinksArr = [NSMutableArray arrayWithCapacity:0];  
  170.                 for (NSTextCheckingResult *result in metchedArr) {  
  171.                     NSRange range = result.range;  
  172.                     NSString *urlWithHREF = [responseStr substringWithRange:range];  
  173.                     if (urlWithHREF && [urlWithHREF length]) {  
  174.                         NSArray *urlParts = [urlWithHREF componentsSeparatedByString:@"\""];  
  175.                         if (urlParts && [urlParts count]>2) {  
  176.                             NSString *musicURL = [urlParts objectAtIndex:1];  
  177.                               
  178.                             //把第一个获得的地址存到首选里去  
  179.                             NSString *songURL = [dictionary objectForKey:@"firstChoose_url"];  
  180.                             if (!songURL || [songURL length]<1) {  
  181.                                 [dictionary setObject:musicURL forKey:@"firstChoose_url"];  
  182.                             }else{  
  183.                                 //去重  
  184.                                 if (![musicURL isEqualToString:songURL]) {  
  185.                                     //用数组保存其他链接  
  186.                                     [otherLinksArr addObject:musicURL];  
  187.                                 }  
  188.                             }  
  189.                         }  
  190.                     }  
  191.                 }  
  192.                   
  193.                 //保存其他链接到字典  
  194.                 [dictionary setObject:otherLinksArr forKey:@"other_link"];  
  195.             }  
  196.               
  197.             //如果下载地址解析失败,一下内容都没有必要存在  
  198.             NSString *firstChoose_url = [dictionary objectForKey:@"firstChoose_url"];  
  199.             if (firstChoose_url && [firstChoose_url length]) {  
  200.                 /**  
  201.                  2.查找歌曲的名称  
  202.                  **/  
  203.                 NSString *xPath = @"//*[@class=\"info1\"]";  
  204.                 TFHppleElement *info1Node = [help peekAtSearchWithXPathQuery:xPath];  
  205.                 TFHppleElement *aNode = info1Node.firstChild;  
  206.                 NSString *songName = [aNode objectForKey:@"title"];  
  207.                 if (songName && [songName length]) {  
  208.                     [dictionary setObject:songName forKey:@"song"];  
  209.                 }else{  
  210.                     [dictionary setObject:@"Unknown" forKey:@"song"];  
  211.                 }  
  212.                   
  213.                   
  214.                 /**  
  215.                  3.查找艺术家  
  216.                  **/  
  217.                 NSArray *info1Children = info1Node.children;  
  218.                 if (info1Children && [info1Children count]) {  
  219.                     BOOL isArtistTag = NO;  
  220.                     for (TFHppleElement *node in info1Children) {  
  221.                         if ([node.tagName isEqualToString:@"a"] && isArtistTag) {  
  222.                             NSString *artist = [node objectForKey:@"title"];  
  223.                             if (artist && [artist length]) {  
  224.                                 [dictionary setObject:artist forKey:@"artist"];  
  225.                                 isArtistTag =NO;  
  226.                             }  
  227.                         }  
  228.                         isArtistTag = YES;  
  229.                     }  
  230.                 }  
  231.                 NSString *hasArtist = [dictionary objectForKey:@"artist"];  
  232.                 if (!hasArtist || [hasArtist length]<1) {  
  233.                     [dictionary setObject:@"Unknown" forKey:@"artist"];  
  234.                 }  
  235.                   
  236.                 /**  
  237.                  4.查找歌曲的大小  
  238.                  **/  
  239.                 xPath = @"//*[@class=\"info2\"]";  
  240.                 TFHppleElement *info2Node = [help peekAtSearchWithXPathQuery:xPath];  
  241.                 NSArray *children = info2Node.children;  
  242.                 if (children && [children count]) {  
  243.                     for (TFHppleElement *node in children) {  
  244.                         if ([node.tagName isEqualToString:@"strong"]) {  
  245.                             NSString *sizeDesc = node.content;  
  246.                             if (sizeDesc && [sizeDesc length]) {  
  247.                                 [dictionary setObject:sizeDesc forKey:@"size"];  
  248.                             }  
  249.                         }  
  250.                     }  
  251.                 }  
  252.                 NSString *hasSize = [dictionary objectForKey:@"size"];  
  253.                 if (!hasSize || [hasSize length]<1) {  
  254.                     [dictionary setObject:@"Unknown" forKey:@"size"];  
  255.                 }  
  256.                   
  257.                 //NSLog(@"***************歌曲信息:%@",dictionary);  
  258.                   
  259.                 //返回字典  
  260.                 return dictionary;  
  261.             }  
  262.             return nil;  
  263.         }else{  
  264.             //重新请求,直到获取成功  
  265.             [self getMusicInfoByJumpToUrl:jumpToUrl];  
  266.         }  
  267.     }  
  268.     return nil;  
  269. }  
  270.   
  271. - (void)runToGetSongInfoFromSogouWithKeyword:(NSString*)kw pageNumber:(NSInteger)pgNum{  
  272.     if (kw && [kw length]) {  
  273.         NSMutableArray *songsInfoArr = [NSMutableArray arrayWithCapacity:0];  
  274.           
  275.         NSArray *songsURLsArr = [self getJumpToDownloadPageURLsWithKeyword:kw pageNumber:pgNum];  
  276.           
  277.         //如果第一次请求失败,再次请求  
  278.         if (!songsInfoArr || [songsInfoArr count]<1) {  
  279.             songsURLsArr = [self getJumpToDownloadPageURLsWithKeyword:kw pageNumber:pgNum];  
  280.         }  
  281.         //如果第二次请求失败,再次请求  
  282.         if (!songsInfoArr || [songsInfoArr count]<1) {  
  283.             songsURLsArr = [self getJumpToDownloadPageURLsWithKeyword:kw pageNumber:pgNum];  
  284.         }  
  285.           
  286.         if (songsURLsArr && [songsURLsArr count]) {  
  287.             for (NSString *url in songsURLsArr) {  
  288.                 NSDictionary *songInfo = [self getMusicInfoByJumpToUrl:url];  
  289.                 if (songInfo && [songInfo count]) {  
  290.                     [songsInfoArr addObject:songInfo];  
  291.                 }  
  292.             }  
  293.         }  
  294.           
  295.         if ([songsInfoArr count]) {  
  296.             [[NSNotificationCenter defaultCenter] postNotificationName:SogouMusicParseSuccessNotification  
  297.                                                                 object:nil userInfo:[NSDictionary dictionaryWithObject:songsInfoArr forKey:@"songsInfo"]];  
  298.         }else{  
  299.             [[NSNotificationCenter defaultCenter] postNotificationName:SogouMusicParseFailedNotification  
  300.                                                                 object:nil userInfo:[NSDictionary dictionaryWithObject:@"This page does not exist"   
  301.                                                                                                                 forKey:@"msg"]];  
  302.         }  
  303.     }else{  
  304.         [[NSNotificationCenter defaultCenter] postNotificationName:SogouMusicParseFailedNotification  
  305.                                                             object:nil userInfo:[NSDictionary dictionaryWithObject:@"Check what you've been input"   
  306.                                                                                                             forKey:@"msg"]];  
  307.     }  
  308. }  
  309. @end  
posted @ 2012-04-12 22:05  生活不是用来挥霍的  阅读(1189)  评论(0编辑  收藏  举报