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

45 篇文章 0 订阅
43 篇文章 0 订阅

//
// SougouMusicParser.h
//
// Created by scott.8an@gmail.com on 12-3-13.
// Copyright (c) 2012年 littleworn llc. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "ASIHTTPRequest.h"
#import "ASINetworkQueue.h"
#import "TFHpple.h"
#import "XPathQuery.h"
#import "TFHppleElement.h"
#import "DataType.h"

//页面地址
#define kRequestURL(s_songName,i_pageNumber) \
[NSString stringWithFormat:@"http://mp3.sogou.com/music.so?pf=mp3&query=%@&page=%i&w=02009900&dr=1",s_songName,i_pageNumber]

@interface SogouMusicParser : NSObject

+ (SogouMusicParser*)shareInstance;

/**
发送成功通知的数组结构:
[
{
"song"="save me",
"artist"="Queen",
"size"="4.38M",
"firstChoose_url"="http://ziyuan1.myi.cn/film/YINYUE/fir/firT1563.mp3",
"other_link"= [
"http://mul1.tximg.cn/music/group/bbs/mp3/7/090528/1243462409315.mp3",
"http://api.ning.com/files/SRIkTa2lzwqL1jt26257Yzj3TCFZ6jAJD2HaYhYB*N469JhRrd01xDttiHqjJD7K9WkWr69u6LnXChFfA2Wid0jWUfiIB33m/f.i.r._.mp3"
]
},...
]
**/
- (void)runToGetSongInfoFromSogouWithKeyword:(NSString*)kw pageNumber:(NSInteger)pgNum;
@end




//
// SougouMusicParser.m
//
// Created by scott.8an@gmail.com on 12-3-13.
// Copyright (c) 2012年 littleworn llc. All rights reserved.
//

#import "SogouMusicParser.h"

NSString *const SogouMusicParseSuccessNotification = @"SogouMusicParseSuccessNotification";
NSString *const SogouMusicParseFailedNotification = @"SogouMusicParseFailedNotification";

static SogouMusicParser *parser_ = nil;

@interface SogouMusicParser (Private)
//获得跳转地址的urls
/**
[
"http://mp3.sogou.com/down.so?gid=11950F9C68D7EDE7&globalId=1f940cf0056326c8&query=%CE%D2%C",
"http://mp3.sogou.com/down.so?gid=11950F9C68D7EDE7&globalId=1f940cf0056326c8&query=%CE%D2%C",
...
]
**/
- (NSArray*)getJumpToDownloadPageURLsWithKeyword:(NSString*)kw pageNumber:(int)pgNum;

/**
返回字典结构:
{
"song"="save me",
"artist"="Queen",
"size"="4.38M",
"firstChoose_url"="http://ziyuan1.myi.cn/film/YINYUE/fir/firT1563.mp3",
"other_link"= [
"http://mul1.tximg.cn/music/group/bbs/mp3/7/090528/1243462409315.mp3",
"http://api.ning.com/files/SRIkTa2lzwqL1jt26257Yzj3TCFZ6jAJD2HaYhYB*N469JhRrd01xDttiHqjJD7K9WkWr69u6LnXChFfA2Wid0jWUfiIB33m/f.i.r._.mp3"
]
}
**/
- (NSDictionary*)getMusicInfoByJumpToUrl:(NSString*)jumpToUrl;
@end


@implementation SogouMusicParser

+ (SogouMusicParser*)shareInstance{
if (!parser_) {
parser_ = [[self alloc] init];
}
return parser_;
}

- (NSArray*)getJumpToDownloadPageURLsWithKeyword:(NSString*)kw pageNumber:(int)pgNum{
if (kw && [kw length]) {
//初始化需要返回的数组
NSMutableArray *urlsArr = [NSMutableArray arrayWithCapacity:0];

//去掉搜索条件两端空格
NSString *pureKW = [kw stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

//用 + 号连接需要要搜索的绑定条件
NSArray *kwArr = [pureKW componentsSeparatedByString:@" "];
NSMutableString *neededKw = [NSMutableString stringWithCapacity:0];
if (kwArr && [kwArr count]) {
for (NSString *str in kwArr) {
[neededKw appendFormat:@"%@+",str];
}

//去掉最后一个 + 号
[neededKw deleteCharactersInRange:NSMakeRange([neededKw length]-1, 1)];
}else{
neededKw = (NSMutableString*)kw;
}
//对url编码
NSString *requestURLStr = kRequestURL(neededKw,pgNum);
NSString *requestURLStrEnc = [requestURLStr stringByAddingPercentEscapesUsingEncoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000)];

//请求页面地址
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:requestURLStrEnc]];
[request startSynchronous];

//获得返回数据
//NSString *responseStr = [request responseString];
NSData *responseData = [request responseData];
//NSLog(@"%@",responseStr);

if (responseData) {
TFHpple *help = [TFHpple hppleWithHTMLData:responseData];
if (help) {
//用xpath解析获得歌曲的跳转地址
//获得tbody节点
NSString *xPath = @"//*[@id='songlist']";
TFHppleElement *tableNode = [help peekAtSearchWithXPathQuery:xPath];
TFHppleElement *tBodyNode = tableNode.firstChild;
if (tBodyNode) {
NSMutableArray *childrenNodes = (NSMutableArray*)tBodyNode.children;
if (childrenNodes && [childrenNodes count]) {
//移除第一个node
[childrenNodes removeObjectAtIndex:0];
for (TFHppleElement *element in childrenNodes) {
NSArray *tdNodeArr = element.children;
if (tdNodeArr && [tdNodeArr count]) {
for (TFHppleElement *tdEle in tdNodeArr) {
TFHppleElement *aNode = tdEle.firstChild;
if (aNode && [[aNode objectForKey:@"action"] isEqualToString:@"down"]) {
/**
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','
','width=431,height=495,scrollbars=no');
uigsPB('consume=music_down&music_down=28');return(false);
*/
NSString *urlThatMixed = [aNode objectForKey:@"onclick"];
NSArray *urlParts = [urlThatMixed componentsSeparatedByString:@"'"];
//取第二个作为uri
NSString *uri = [urlParts objectAtIndex:1];

if (uri && [uri length]) {
NSString *url = [NSString stringWithFormat:@"http://mp3.sogou.com%@",uri];
//NSLog(@"组合新的跳转地址:http://mp3.sogou.com%@",uri);

[urlsArr addObject:url];
}
}
}
}
}
if ([urlsArr count]) {
return urlsArr;
}
}
}
}
}else{
//再次尝试
[self getJumpToDownloadPageURLsWithKeyword:kw pageNumber:pgNum];
}
}
return nil;
}

- (NSDictionary*)getMusicInfoByJumpToUrl:(NSString*)jumpToUrl{
if (jumpToUrl && [jumpToUrl length]) {
//获得下载页面,不需要编码,因为获得的数据已经是编码过了的
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:jumpToUrl]];
[request startSynchronous];

//获得返回界面
NSString *responseStr = [request responseString];
NSData *responseData = [request responseData];
// NSLog(@"返回下载界面的网页信息:%@",responseStr);

if (responseData) {
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:0];

//解析页面
TFHpple *help = [TFHpple hppleWithHTMLData:responseData];

/**
1.查找歌曲的下载地址
**/

//href="..+.mp3"
NSString *pattern = @"href=\"..+.mp3\"";
NSRegularExpression *exp = [NSRegularExpression regularExpressionWithPattern:pattern
options:NSRegularExpressionCaseInsensitive
error:nil];
NSArray *metchedArr = [exp matchesInString:responseStr options:NSMatchingReportProgress range:NSMakeRange(0, [responseStr length])];

if (metchedArr && [metchedArr count]) {
//用数组保存其他连接
NSMutableArray *otherLinksArr = [NSMutableArray arrayWithCapacity:0];
for (NSTextCheckingResult *result in metchedArr) {
NSRange range = result.range;
NSString *urlWithHREF = [responseStr substringWithRange:range];
if (urlWithHREF && [urlWithHREF length]) {
NSArray *urlParts = [urlWithHREF componentsSeparatedByString:@"\""];
if (urlParts && [urlParts count]>2) {
NSString *musicURL = [urlParts objectAtIndex:1];

//把第一个获得的地址存到首选里去
NSString *songURL = [dictionary objectForKey:@"firstChoose_url"];
if (!songURL || [songURL length]<1) {
[dictionary setObject:musicURL forKey:@"firstChoose_url"];
}else{
//去重
if (![musicURL isEqualToString:songURL]) {
//用数组保存其他链接
[otherLinksArr addObject:musicURL];
}
}
}
}
}

//保存其他链接到字典
[dictionary setObject:otherLinksArr forKey:@"other_link"];
}

//如果下载地址解析失败,一下内容都没有必要存在
NSString *firstChoose_url = [dictionary objectForKey:@"firstChoose_url"];
if (firstChoose_url && [firstChoose_url length]) {
/**
2.查找歌曲的名称
**/
NSString *xPath = @"//*[@class=\"info1\"]";
TFHppleElement *info1Node = [help peekAtSearchWithXPathQuery:xPath];
TFHppleElement *aNode = info1Node.firstChild;
NSString *songName = [aNode objectForKey:@"title"];
if (songName && [songName length]) {
[dictionary setObject:songName forKey:@"song"];
}else{
[dictionary setObject:@"Unknown" forKey:@"song"];
}


/**
3.查找艺术家
**/
NSArray *info1Children = info1Node.children;
if (info1Children && [info1Children count]) {
BOOL isArtistTag = NO;
for (TFHppleElement *node in info1Children) {
if ([node.tagName isEqualToString:@"a"] && isArtistTag) {
NSString *artist = [node objectForKey:@"title"];
if (artist && [artist length]) {
[dictionary setObject:artist forKey:@"artist"];
isArtistTag =NO;
}
}
isArtistTag = YES;
}
}
NSString *hasArtist = [dictionary objectForKey:@"artist"];
if (!hasArtist || [hasArtist length]<1) {
[dictionary setObject:@"Unknown" forKey:@"artist"];
}

/**
4.查找歌曲的大小
**/
xPath = @"//*[@class=\"info2\"]";
TFHppleElement *info2Node = [help peekAtSearchWithXPathQuery:xPath];
NSArray *children = info2Node.children;
if (children && [children count]) {
for (TFHppleElement *node in children) {
if ([node.tagName isEqualToString:@"strong"]) {
NSString *sizeDesc = node.content;
if (sizeDesc && [sizeDesc length]) {
[dictionary setObject:sizeDesc forKey:@"size"];
}
}
}
}
NSString *hasSize = [dictionary objectForKey:@"size"];
if (!hasSize || [hasSize length]<1) {
[dictionary setObject:@"Unknown" forKey:@"size"];
}

//NSLog(@"***************歌曲信息:%@",dictionary);

//返回字典
return dictionary;
}
return nil;
}else{
//重新请求,直到获取成功
[self getMusicInfoByJumpToUrl:jumpToUrl];
}
}
return nil;
}

- (void)runToGetSongInfoFromSogouWithKeyword:(NSString*)kw pageNumber:(NSInteger)pgNum{
if (kw && [kw length]) {
NSMutableArray *songsInfoArr = [NSMutableArray arrayWithCapacity:0];

NSArray *songsURLsArr = [self getJumpToDownloadPageURLsWithKeyword:kw pageNumber:pgNum];

//如果第一次请求失败,再次请求
if (!songsInfoArr || [songsInfoArr count]<1) {
songsURLsArr = [self getJumpToDownloadPageURLsWithKeyword:kw pageNumber:pgNum];
}
//如果第二次请求失败,再次请求
if (!songsInfoArr || [songsInfoArr count]<1) {
songsURLsArr = [self getJumpToDownloadPageURLsWithKeyword:kw pageNumber:pgNum];
}

if (songsURLsArr && [songsURLsArr count]) {
for (NSString *url in songsURLsArr) {
NSDictionary *songInfo = [self getMusicInfoByJumpToUrl:url];
if (songInfo && [songInfo count]) {
[songsInfoArr addObject:songInfo];
}
}
}

if ([songsInfoArr count]) {
[[NSNotificationCenter defaultCenter] postNotificationName:SogouMusicParseSuccessNotification
object:nil userInfo:[NSDictionary dictionaryWithObject:songsInfoArr forKey:@"songsInfo"]];
}else{
[[NSNotificationCenter defaultCenter] postNotificationName:SogouMusicParseFailedNotification
object:nil userInfo:[NSDictionary dictionaryWithObject:@"This page does not exist"
forKey:@"msg"]];
}
}else{
[[NSNotificationCenter defaultCenter] postNotificationName:SogouMusicParseFailedNotification
object:nil userInfo:[NSDictionary dictionaryWithObject:@"Check what you've been input"
forKey:@"msg"]];
}
}
@end

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值