批量下载虾米已下载歌曲(新)

提醒:本文最后更新于 4087 天前,文中所描述的信息可能已发生改变,请谨慎使用。

前言

呵呵,没错,公子我又再次光荣的把硬盘搞挂了,然后音乐又没了!鉴于之前已经有过一次经验(批量下载虾米已下载歌曲),所以本以为这次也会轻而易举了的。没想到居然在我写出那篇日志后没多久,官方居然各种更新(更新页面,下载机制,Flash播放器),然后我那篇日志的方法就没法用了。不过官方这个也都是小改,所以我也只要小改下代码就成啦!哈哈!

有什么变化

首先要说的是虾米官方的下载思路还是没变的,基本上还是之前日志里头说的那样:

在网站点击下载之后,网站向你的账户中未下载列表传递下载歌曲信息,之后未下载列表则返回一个以emoun://特有协议开头的文件,用以打开虾歌(这个和迅雷thunder://以及电骡等的ed2k://是一个道理)。虾歌打开后查询未下载的表单,返回表单中的歌曲,然后下载。同时将未下载列表中的歌曲提交到已下载列表中,并在未下载列表中删除。 - 批量下载虾米已下载歌曲

官方改变的就是下载列表和网站点击下载这两步:

下载列表

老版的是直接显示列表显示每首歌的,新版则是按照下载时间来显示,一次下载为一次订单,订单内再显示此次下载的歌曲。这样正则匹配获取歌曲的ID就需要发生变化了。

点击下载提交订单

以前只要登录后向服务器POST歌曲的ID就能提交订单了。新版则需要提交sign_xiamitoken这两个新参数,三个参数一块POST才行。sign参数暂时还不知道如何算出来的,_xiamitoken则是你的cookies。看源码意外的让我发现了参数居然都直接写在页面里头了,为了简便,我就直接抓取订单页面正则获取这两个参数了。同时还加了判断Referer这种老手段,这个也不算难。

VIP机制

以前是没有VIP的,自从被阿里收购之后就增加了VIP功能。好在现在可以用体验点(以前的红包)购买VIP,15个体验点可以买一个月的VIP,一个月的VIP能免费下100首歌曲。我的歌曲数在400+,花了80个体验店办了半年的,可以免费下600首歌曲。等于用80个体验店下600首歌的意思,变相的节省了下体验点,哈哈!

解题步骤

一、获取登录COOKIES

这一步和老版还是一样的,直接复制过来吧。

获取登录后的COOKIES文件,方便之后的抓取工作。修改代码中的第2行和第3行,填入自己的账号和密码。如果成功的话,会在该文件的同级目录下得到一个cookies.txt文件。

<?php
$name = ''; //输入你的账号
$password = ''; //输入你的密码
$curl_post = 'email='.$name.'&amp;password='.$password.'&amp;done=/&amp;submit=登 录';
$cookie_file = dirname(__FILE__).'/cookie.txt';
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, &quot;http://www.xiami.com/member/login&quot;);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $curl_post);
curl_setopt($curl, CURLOPT_COOKIEJAR, $cookie_file);
curl_exec($curl);
curl_close($curl);
?>

二、抓取下载列表并提交到未下载列表

这一步因为列表的改变有些许变化。而且新版订单还有个新订单和旧订单之分,真是蛋疼,还得做两次解析。

<?php
set_time_limit(0); //设置成不限制页面运行时间
function get($url) {
    $cookie_file = dirname(__FILE__).'/cookie.txt';
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_COOKIEFILE, $cookie_file);
    $data = curl_exec($curl);
    curl_close($curl);
    return $data;
}
$song = array();
$pageinfo = get('http://www.xiami.com/account/myorders-old');
$preg = '/\…\<\/a\>\<a href\=\"\/account\/myorders-old\/page\/(.*?)\" class\=\"p\_num\">/s';
preg_match_all($preg, $pageinfo, $match);
$page = $match[1][0];
for($i=1;$i<$page;$i++) {
    $data = get("http://www.xiami.com/account/myorders-old/page/".$i);
    $preg = '/\<td class\=\"iname\"\>\<a href\=\"\/song\/(.*?)\"/s';
    preg_match_all($preg, $data, $match);
    foreach($match[1] as $item) $song[] = $item;
}
$pageinfo = get('http://www.xiami.com/account/myorders');
$preg = '/\…\<\/a\>\<a href\=\"\/account\/myorders\/page\/(.*?)\" class\=\"p\_num\">/s';
preg_match_all($preg, $pageinfo, $match);
$page = $match[1][0];
for($i=1;$i<$page;$i++) {
    $data = get("http://www.xiami.com/account/myorders-old/page/".$i);
    $preg = '/\<td class\=\"iname\"\>\<a href\=\"\/song\/(.*?)\"/s';
    preg_match_all($preg, $data, $match);
    foreach($match[1] as $item) $song[] = $item;
}
$song = array_unique($song, SORT_NUMERIC);
echo 'var song = new Array('.implode(',', $song).')';
?>

批量提交下载歌曲

我之前也讲了,新版新增sign_xiamitoken两个参数,同时还增加了Referer验证。整体代码还是采用上版中的PHP+AJAX异步提交,只是在PHP部分有稍许修改。

将上一步得到的代码复制替换掉相同的那部分,保存为download.html

<script type="text/javascript">
//将第二步获得的代码复制到下面
var song = new Array(1769629171,3338870,1769902385,1770432131,2868586,1770149760,367633,1769832130,35526,1769962750,1770551145,1770457081,3486103,1769400110,127903,3367334,2078855,71830,376007,376015,2074918,2730,1770450144,3455520,79157,79151,81366,65256,390070,2138604,1770345727,376050,376006,149193,388168,1769665592,3497062,1769236069,3632104,1768923954,1769491757,3608275,2092882,1770354410,3480460,3620143,2095376,2561774,3664677,1770462404,1769056924,3527076,2126340,2089410,1769177482,2083322,1769831952,1769316186,1770524409,1769517803,1190507,1964547,1769107542,3486203,1769686818,1769028326,1858814,2084011,1769235816,1770614545,2083187,2605276,378268,2515019,1122167,1769176497,3302053,2083102,3638520,189072,371017,1770168732,1083760,2122948,2070331,2128868,3319126,2561592,1381654,3441719,1768939471,2091290,2098665,2067235,1770060224,3562953,54342,1769831786,1770145312,76323,2067242,173117,136054,1770068043,1769833104,1769833105,1769833106,1769833107,1769833108,2082305,1768989931,1769356638,1769082273,1769776879,1769740304,1205851,1768984809,1769102373,1769740095,1768989928,1769381931,1769227674,3599015,1768962602,3463177,1769381938,1769381935,1769381934,1769381932,3410377,2067242,3381901,3381903,373969,2072395,373971,373990,374039,3381910,3381911,3381912,382134,378711,193010,162269,143775,127673,120041,89443,52732,382512,383210,1769274527,1769004670,1768958960,3599311,3365855,2314604,2080987,2073790,385907,115384,374057,377936,380029,382560,382852,383962,33806,378041,380287,385729,385760,388406,389153,381833,83126,386773,389072,389080,389077,43542,52726,375183,382821,384595,385074,386954,373818,376387,378307,379302,382777,384646,384670,385137,385976,386073,386347,2342433,3550893,1769699970,2095102,2095107,2017034,2286524,2342421,2286523,3338183,1768988423,2286527,2380720,3464931,1176114,1769334977,2155384,1769839800,3225258,2091936,1769334987,3187867,2095104,3413844,1769072635,1007695,3636957,3467770,1768940269,1769292436,1769850021,1769102619,3409064,1769870173,1769850022,1769850019,1769463117,3446206,2028877,2136483,1769072646,1769291745,1769072643,1769113798,196142,3187959,2079575,2286522,2079581,2385273,1769673320,3513664,1769071426,3502285,1769801604,1769801605,3484274,1769303054,1769303056,1769303057,1769303058,1769303059,1769303060,1769303061,1769303062,1769303055,1768914983,378646,3586293,1769830111,1769830112,1769830113,1769830114,1769830115,1769830116,1769830117,1769830118,1769830119,1769830120,1769570445,);

//复制结束

//下面的代码不需要修改 
var XHR; //定义一个全局对象 
function xm_download(id){  
    if(window.ActiveXObject){//IE的低版本系类 
        XHR=new ActiveXObject('Microsoft.XMLHTTP');
    }else if(window.XMLHttpRequest){//非IE系列的浏览器,但包括IE7 IE8 
        XHR=new XMLHttpRequest(); 
    } 
    XHR.open("GET","download.php?id="+id,true);        
    XHR.send(null); 
} 
for (var i=0;i<song.length;i++) {
    xm_download(song[i]);
}
</script>

将下面的代码保存为download.php,放在与download.html同级目录中

<?php
$cookie_file = dirname(__FILE__).'/cookie.txt'; //登录COOKIES文件地址
$id = $_GET['id'];
$url = "http://www.xiami.com/download/pay?id=$id";
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_COOKIEFILE, $cookie_file);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($curl);
curl_close($curl);
$preg = '/\<input type\=\"hidden\" name\=\"sign\" id\=\"sign\" value\=\"(.*?)" \/\>/s';
preg_match_all($preg, $data, $match);
$sign = $match[1][0];
$pieces = explode('<input type="hidden" value="', $data);
$piece = end($pieces);
$cookies = explode('"', $piece);
$cookie = $cookies[0];
$data = "song_ids[]=$id&amp;use_vip=1&amp;down=1&amp;inpour_amount=0&amp;sign=$sign&amp;_xiamitoken=$cookie";
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_COOKIEFILE, $cookie_file);
curl_setopt($curl, CURLOPT_REFERER, $url);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);    
$data = curl_exec($curl);
curl_close($curl);
?>

四、打开虾歌查询订单

最后一步是打开虾歌,选择“文件”→“检查未完成下载”,静候片刻你就可以欢呼了!之后静静等待虾歌批量下载成功就好了。

Avatar
怡红公子 擅长前端和 Node.js 服务端方向。热爱开源时常在 Github 上活跃,也是博客爱好者,喜欢将所学内容总结成文章分享给他人。

24 评论

FF Chrome31.0 Mac OS 10.9.1
2014-01-25 15:24:05 回复

你好,我尝试了下下载,发现vip帐号(也就是网页只能下载200首歌曲) 通过你的脚本实际上还是会扣除下载次数的 对吗?

公子 Chrome32.0 Windows 7
2014-01-26 02:01:12 回复

@FF 嗯,是的,虾米这个实在是变态,下载之前下过的歌曲还是会扣除体验点什么的,我都没扣过两次了OAQ…几百的体验点就没了啊!!好在我体验点还算多,嘿嘿~

冷笑话精选 IE6.0 Windows XP
2014-01-13 10:35:26 回复

一位女士上了车,所有的座位都占满了。一位先生起身让座,这位女士当仁不让地坐了下来。 先生俯下身问道:“夫人,您说什么来着?”女士惊讶地说:“我什么也没有说呀!”“对不起,我还以为您说‘谢谢’了呢!”
一次坐公交车,上来二位老大爷,我给让了个坐,旁边一哥们儿无动于衷,我站在他身边恶狠狠的瞪了他一眼。 本来想让他让个座给另外一个大爷,谁知他恶狠狠的回瞪我一眼,于是我说:“看什么看,赶紧给大爷让座!”可能是我长的太凶了,他赶紧起来对我说:大爷您坐吧
公交车上人很多,好不容易找到一个位子,坐着就睡着了。迷迷糊糊中,被刹车惊醒,感觉有一个人抱着小孩的站在我身旁。我连忙从座位上站起来,大声音的说:“您抱着孩子,给你让座,你快坐下吧!”全车人的目光都投了过来。我定睛一看,只见我身旁一位小MM红着脸,抱着一只毛绒玩具!

冷笑话精选 IE6.0 Windows XP
2014-01-13 10:35:21 回复

老李喜欢上了打猎,几个月过去了连只兔子也没打着。 同伴们都嘲笑他,于是老李买了只活兔子拴在离自己几十米的地方,扣动扳机后高兴地去拣兔子,谁知道过去一看,老李把绳子打断兔子跑了。

猫大叔 Firefox25.0 Windows 7
2013-11-04 07:32:10 回复

回复之后又正常显示了.

猫大叔 Firefox25.0 Windows 7
2013-11-04 07:30:01 回复

公子还是这么努力啊…为毛我的火狐这个页面的名字显示不全呢?TE出0.9了.你的宝贝们是不是要再更新下?

怡红公子 Chrome30.0 Windows 7
2013-11-04 07:37:52 回复

@猫大叔 嗯,等0.9比较稳定了再更新一下吧,现在好像还在改,而且最近没空,咳咳…

苏晓晨 Chrome29.0 Windows 8
2013-09-23 01:42:58 回复

我是直接用Network那个功能获取地址然后手动一首一首下载的……

公子 Chrome29.0 Windows 7
2013-09-23 01:59:51 回复

@苏晓晨 哎呀呀,一首一首下载什么的太不AWESOME啦这才不是我们应该干的事情嘛不过如果没开VIP的话网络试听的地址应该是低码率的吧,嘛,不过开了VIP的话就无所谓了

苏晓晨 Chrome29.0 Windows 8
2013-09-23 02:43:03 回复

@公子不是虾米,那太LOW了,说的是豆瓣;似乎有些偏题了。

公子 Chrome29.0 Windows 7
2013-09-23 03:09:45 回复

@苏晓晨啊,豆瓣啊,文艺小青年的说。不过拿豆瓣来下歌,这个…是不是太大材小用了0_0…豆瓣我一般写代码写文章的时候会开着==!,平常的话都转自己的红心播放器听歌了0_0
p.s. 跑题没关系,我最喜欢干的事情就是跑题了←

苏晓晨 Chrome29.0 Windows 8
2013-09-23 09:31:46 回复

@公子豆瓣有很多好听未公开且不提供下载的歌。

公子 Chrome29.0 Windows 7
2013-09-23 11:09:55 回复

@苏晓晨 嗯,豆瓣音乐人的作品么?看来你比较喜欢这些小众歌曲啦,果然是文艺范十足啊_ 看来你不是我的菜o(╯□╰)o…不过这种情况就根本不适合批量下载吧,顶多就一张专辑的量,看来我所谓的手点太不AWESOME实在是片面了一点呢。
p.s. 比较好奇你所谓的未公开的歌你是肿么知道很好听的…=——=!口口相传,交口称赞么?

苏晓晨 Chrome29.0 Windows 8
2013-09-25 10:21:25 回复

@公子未公开指的是仅在一处豆瓣有资源,未在其他地方公开。

公子 Chrome29.0 Windows 7
2013-09-25 11:56:58 回复

@苏晓晨 原来如此~

微历史 Firefox23.0 Windows XP
2013-09-13 02:59:53 回复

现在下载的少了吧,一般都在线听了

公子 Chrome29.0 Windows 7
2013-09-13 03:01:40 回复

@微历史 恩哼,我喜欢下载的,而且放手机上什么的多方便啊~

Firefox23.0 Windows 7
2013-09-09 15:51:35 回复

其实我应该是沙发的,可是忘了
把硬盘搞坏的人都是些什么人啊啊啊

公子 Chrome29.0 Windows 7
2013-09-10 02:12:32 回复

@安忘了沙发的人都是些什么人啊啊啊

Jclyn Chrome29.0 Windows 7
2013-09-23 01:55:20 回复

@安 他是禽兽哈哈哈哈哈哈哈哈哈

小十 Chrome31.0 Windows 7
2013-09-09 03:23:19 回复

太厉害了公子!

公子 Chrome29.0 Windows 7
2013-09-09 09:03:57 回复

@小十额,比起你们来说还差太多了T_T…

Jclyn Chrome28.0 iOS 6.1.3
2013-09-05 14:49:44 回复

我这是发自肺腑的声音,不容小觑!!!
多加一个鸡腿谢谢

Jclyn Chrome28.0 iOS 6.1.3
2013-09-05 14:47:01 回复

好好好!!!