1
顶一下

  近期写了一个android音乐播放器,但是苦于找不到可以自动下载歌词的网站。网上搜的那个已经不能用了。这时候想起可以调用百度或者谷歌的接口来搜索歌词,由于谷歌刚刚推出了谷歌音乐,于是我就想着去尝试下。

   进入谷歌音乐的主页,然后随便输了首歌去搜索,跳转至歌曲搜索。发现真的有歌词,可惜歌词不是嵌套在网页里的,并且打开歌词网页的地址里包含的是歌词的id,这可这么半呢?

   于是我就去搜索页面寻找歌曲的id,果然在html源代码中找到了歌曲的id,然后我就用这个id拼接在歌词网址的字符串中,最后顺利地进入了歌词页面。

   不过歌词页面中的信息很少,连歌词都是从别的地方读取过来的,html源代码中也没有歌词相应的地址。还好,在页面的框架信息中我看到了歌词的地址,在浏览器输入后就可以直接下载,并且下载后的文件就是歌曲的歌词,不含其他信息。

    这样就有思路了:

    1.接收参数为歌曲名和歌手(这样可以准确的定位歌词文件),然后把参数拼接在查询字符串后面,进行歌词页面的查询。

    2.获取歌词页面的html源代码并进行解析,获取歌曲的id

    3.将歌曲的id拼接在歌词框架页面地址的后面,获取歌词框架页面的html源代码

    4.解析框架页面的源代码,获取歌词下载地址。

    5.下载歌词并保存至文件。

需要注意的是:

1.谷歌音乐的歌曲、歌手都不是很多,有些歌曲可能搜索不到歌词,甚至谷歌就没有收录这些歌曲。

2.谷歌服务器不稳定,歌词可能会下载失败,原因大家都懂得。

3.下载的歌词默认放在工程目录下,可以自行修改歌词位置。

4.谷歌音乐页面编码都是UTF-8的,不需要考虑乱码的问题。

PS:本程序仅仅是抛砖引玉,具体怎么使用就看大家的了。

下面上代码:

工具类

 

[java]
  1. <span style=”font-family:FangSong_GB2312;”><span style=”font-size: 14px;”></span></span><pre name=”code” class=”java”>package com.zyc.download_lrc;
  2. /**
  3.  * Get lrc from google music
  4.  * Version 1.00
  5.  * @author zyc
  6.  * 2012.2.2
  7.  */
  8. /*
  9.  * Step:
  10.  * 1.Input music’s name and artist,use google music search engine
  11.  * The url like ”http://www.google.cn/music/search?q=name+artist”
  12.  * 2.Get music id,the id is starts with ”http://g.top100.cn/16667639/html/lyrics.html?id”
  13.  * and id is after
  14.  * 3.Use id to get lrc framework html,find download lrc url
  15.  * 4.download lrc
  16.  * 5.write lrc to file
  17.  *
  18.  * NOTICE:google work may abnormal,you known
  19.  */
  20. import java.io.BufferedReader;
  21. import java.io.File;
  22. import java.io.FileWriter;
  23. import java.io.IOException;
  24. import java.io.InputStreamReader;
  25. import java.net.SocketTimeoutException;
  26. import java.net.URL;
  27. import java.net.URLConnection;
  28. public class DownloadGoogleLrcTool {
  29.     /*music info start,but can’t get id from this,because the music has no lrc*/
  30.     private final static String ID_HEAD_FLAG = ”<!–freemusic”;
  31.     /*google music engine search head*/
  32.     private final static String SEARCH_ENGINE_HEAD = ”http://www.google.cn/music/search?q=”;
  33.     /*google music lrc by id head*/
  34.     private final static String SEARCH_ID_URL_HEAD = ”http://www.google.cn/music/top100/lyrics?id=”;
  35.     /*google music id flag*/
  36.     private final static String SEARCH_ID_FLAG = ”http://g.top100.cn/16667639/html/lyrics.html?id”;
  37.     /*google music download url flag*/
  38.     private final static String SEARCH_LRC_DOWNLOAD_URL_FLAG = ”http://lyric.top100.cn/”;
  39.     /*”%3D” means ”=”*/
  40.     private final static String SEARCH_HTML_EQUAL = ”%3D”;
  41.     private final static String END_FLAG = ”\\”;
  42.     private final static String LRC_SUFFIX = ”.lrc”;
  43.     private final static String LINE_END = ”\n”;
  44.     /*google music can’t connect return code”*/
  45.     private final static String GOOGLE_SB_RETURN_CODE = ”502″;
  46.     /*error message,you know”*/
  47.     private final static String GOOGLE_SB_MESSAGE = ”google抽风中…你懂的\n请稍后再试”;
  48.     private final static String SPACE = ” ”;
  49.     /*”%20″ means ” ”*/
  50.     private final static String HTML_SPACE = ”%20″;
  51.     private final static String HTML_URL_HEAD = ”http://”;
  52.     /*id is letter and number”*/
  53.     private final static String ID_MATCH = ”^[A-Za-z0-9]+{1}quot;;
  54.     /*download message*/
  55.     private final static String CANNOT_FIND_LEC_MESSAGE = ”无法找到歌词”;
  56.     private final static String FAIL_MESSAGE = ”下载歌曲 %s-%s 歌词 失败!\n原因:”;
  57.     private final static String SUCCESS_MESSAGE = ”下载歌曲 %s-%s 歌词 成功!\n歌词位置: %s\n”;
  58.     private final static String DOWNLOADING_MESSAGE = ”正在下载歌曲 %s-%s 歌词…\n”;
  59.     /*time out message*/
  60.     private final static String DOWNLOADING_CONNECT_TIME_OUT = ”connect timed out”;
  61.     private final static String DOWNLOADING_CONNECT_TIME_OUT_MESSAGE = ”连接超时,请检查网络配置”;
  62.     private final static String DOWNLOADING_UNKNOWN_MESSAGE = ”未知”;
  63.     /*set timeout = 5s*/
  64.     private final static long CONNECT_TIME_OUT = 5000;
  65.     /*set http proxy,if don’t use http proxy,set it false*/
  66.     private final static boolean USE_HTTP_PROXY = true;
  67.     private final static String FAIL_WRITE_FILE_MESSAGE = ”写入文件失败!”;
  68.     public static void downloadLrcFromGoogle(String name,String artist){
  69.         try {
  70.             System.out.printf(DOWNLOADING_MESSAGE,name,artist);
  71.             /*get lrc*/
  72.             String lrc = downloadLrc(name,artist);
  73.             if(lrc != null){
  74.                 /*write lrc to file*/
  75.                 String fileName = name + LRC_SUFFIX;
  76.                 File file = new File(fileName);
  77.                 writeToFile(file, lrc);
  78.                 System.out.printf(SUCCESS_MESSAGE, name,artist,file.getAbsoluteFile());
  79.             }
  80.             else
  81.                 System.out.println(CANNOT_FIND_LEC_MESSAGE);
  82.         } catch (Exception e) {
  83.             System.out.printf(FAIL_MESSAGE, name,artist);
  84.             if(e.getMessage().contains(GOOGLE_SB_RETURN_CODE))
  85.                 System.out.println(GOOGLE_SB_MESSAGE);
  86.             else if(e.getMessage().contains(DOWNLOADING_CONNECT_TIME_OUT)){
  87.                 System.out.println(DOWNLOADING_CONNECT_TIME_OUT_MESSAGE);
  88.             }
  89.             else {
  90.                 System.out.println(DOWNLOADING_UNKNOWN_MESSAGE);
  91.             }
  92.             //e.printStackTrace();
  93.         }
  94.     }
  95.     private static void init(){
  96.         System.setProperty(“sun.net.client.defaultConnectTimeout”, String.valueOf(CONNECT_TIME_OUT));
  97.         if(USE_HTTP_PROXY){
  98.             //add http proxy setting here
  99.         }
  100.     }
  101.     private static String downloadLrc(String name,String artist) throws IOException,SocketTimeoutException{
  102.         init();
  103.         /*replace ” ” to ”%2d”*/
  104.         name = name.replaceAll(SPACE, HTML_SPACE);
  105.         artist = artist.replaceAll(SPACE, HTML_SPACE);
  106.         String id = getSongId(name, artist);
  107.         /*can’t find id return null”*/
  108.         if(id == null || !id.matches(ID_MATCH)){
  109.             return null;
  110.         }
  111.         String path = getLrcDownloadUrl(id);
  112.         String lrc = null;
  113.         /*if path isn’t start with ”http”//” ignore*/
  114.         if(path.startsWith(HTML_URL_HEAD))
  115.             lrc = doDownloadLrc(path);
  116.         return lrc;
  117.     }
  118.     private static String getSongId(String name,String artist) throws IOException{
  119.         String source = readHtml(SEARCH_ENGINE_HEAD + name + ”+” + artist);
  120.         name = name.replaceAll(HTML_SPACE, SPACE);
  121.         String match01 = ”\”><b>” + name + ”</b>”;
  122.         String match02 = null;
  123.         if(name.contains(SPACE)){
  124.             /*set first letter upper*/
  125.             String[] array = name.split(SPACE);
  126.             for (int i = 0;i < array.length;i++) {
  127.                 char firstChar = array[i].charAt(0);
  128.                 if(firstChar >= ’a' && firstChar <= ’z'){
  129.                     array[i] = array[i].replace(firstChar, (char) (firstChar - 32));//set upper
  130.                 }
  131.             }
  132.             String newName = ”";
  133.             for (int i = 0;i < array.length;i++) {
  134.                 if(i < array.length - 1)
  135.                     newName += array[i] + SPACE;
  136.                 else
  137.                     newName += array[i];
  138.             }
  139.             match02 = ”\”><b>” + newName + ”</b>”;
  140.         }
  141.         if(!source.contains(match01) && match02 != null && !source.contains(match02)){
  142.             /*may other music return*/
  143.             return null;
  144.         }
  145.         int first = source.indexOf(ID_HEAD_FLAG);
  146.         if(first == -1){
  147.             /*no music id*/
  148.             return null;
  149.         }
  150.         int last = source.indexOf(ID_HEAD_FLAG,first + ID_HEAD_FLAG.length());
  151.         if(last != -1){
  152.             /*ignore only a music id,if have some choose first one*/
  153.             source = source.substring(first,last);
  154.         }
  155.         /*find id*/
  156.         int start = source.indexOf(SEARCH_ID_FLAG);
  157.         int mid = source.indexOf(SEARCH_HTML_EQUAL, start);
  158.         int end = source.indexOf(END_FLAG,mid);
  159.         if(start == -1 || mid == -1 || end == -1){
  160.             //can’t find id
  161.             return null;
  162.         }
  163.         String id = source.substring(mid + HTML_SPACE.length(), end);
  164.         return id;
  165.     }
  166.     private static String getLrcDownloadUrl(String id) throws IOException{
  167.         /*set music lrc html url with id*/
  168.         String source = readHtml(SEARCH_ID_URL_HEAD + id);
  169.         int start = source.indexOf(SEARCH_LRC_DOWNLOAD_URL_FLAG);
  170.         int end = source.indexOf(LRC_SUFFIX,start);
  171.         String urlString = source.substring(start, end + LRC_SUFFIX.length());
  172.         return urlString;
  173.     }
  174.     private static String doDownloadLrc(String path) throws IOException{
  175.         /*download lrc*/
  176.         return readHtml(path);
  177.     }
  178.     private static String readHtml(String urlPath) throws IOException{
  179.         /*use google music search engine*/
  180.         URL url = new URL(urlPath);
  181.         /*connect and get html */
  182.         URLConnection conn = url.openConnection();
  183.         BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
  184.         String line = null;
  185.         StringBuilder stringBuilder = new StringBuilder();
  186.         while ((line = reader.readLine()) != null) {
  187.             stringBuilder.append(line + LINE_END);
  188.         }
  189.         return stringBuilder.toString();
  190.     }
  191.     private static void writeToFile(File file,String buffer) throws IOException{
  192.         /*write to file,file name is music’s name + ”.lrc”*/
  193.         FileWriter writer = new FileWriter(file, false);
  194.         try {
  195.             writer.write(buffer);
  196.         } catch (Exception e) {
  197.             System.out.println(FAIL_WRITE_FILE_MESSAGE);
  198.         }finally{
  199.             writer.close();
  200.         }
  201.     }
  202. }

测试类

 

[java]
  1. <span style=”font-family:FangSong_GB2312;”><span style=”font-size: 14px;”></span></span><pre name=”code” class=”java”>package com.zyc.download_lrc;
  2. public class DownloadTest {
  3.     public static void main(String[] args) {
  4.         //only for test
  5.         String name = ”决战斗室”;
  6.         String artist = ”潘玮柏”;
  7.         downloadMusicLrc(name, artist);
  8.     }
  9.     static void downloadMusicLrc(String name,String artist){
  10.         DownloadGoogleLrcTool.downloadLrcFromGoogle(name, artist);
  11.     }
  12. }

测试结果:

 

正在下载歌曲 决战斗室-潘玮柏 歌词…
下载歌曲 决战斗室-潘玮柏 歌词 成功!
歌词位置: /project/DownLoadLrc/决战斗室.lrc

歌词如下:

[ti:决战斗室]
[ar:潘玮柏]
[al:高手]
[00:05.00]
[01:20.44][00:16.69]克制不住 心跳加速
[01:22.27][00:18.67]太兴奋追求战斗我才满足
[01:24.25][00:20.47]角落处 全神贯注
[01:26.25][00:22.57]眼神冰冷像只危险老虎
[01:28.23][00:24.58]拳头蹦带 无法束缚
[01:30.25][00:26.55]脉膊跳动的强度快忍不住
[01:32.22][00:28.51]灯在闪 人群在喊
[01:34.19][00:30.48]抬起头我完全不屑一顾
[01:36.21][00:32.60]Noboby gonna stop me
[01:38.21][00:34.57]沉默中 聆听自己
[01:40.07][00:36.54]Noboby gonna front me
[01:42.23][00:38.51]相信自己 绝不会逃避
[01:44.25][00:40.55]Noboby gonna touch me
[01:46.19][00:42.48]呐喊声全场淹没
[01:48.12][00:44.41]推开门 走出自我
[01:50.06][00:46.22]This is my life my soul
[02:44.39][02:28.08][01:52.15][00:48.47]紧握灵魂的手
[02:45.75][02:29.93][01:54.03][00:50.35]最后一刻战斗
[02:47.86][02:31.96][01:56.10][00:52.38]黑暗恐惧之中
[02:50.61][02:33.71][01:57.84][00:54.19]决战斗室只剩你我
[02:51.86][02:35.86][02:00.09][00:56.38]倒数的计时钟
[02:53.77][02:37.90][02:02.00][00:58.30]胜利才终结转动
[02:57.37][02:41.51][02:05.59][01:01.84]我闭上眼我站在斗室中
[02:59.29][02:43.35][02:07.50][01:03.94]只剩下Oh oh

然后就可以放进手机同步播放了!

搞定!!!