使用Python下载歌词并嵌入歌曲文件中的实现代码


Posted in Python onNovember 13, 2015

使用python扫描本地音乐并下载歌词
这次这个真的是干货哦,昨晚弄了半晚上,,,,从8点吃完饭就开始写,一直到了快12点才弄好,,,新手,伤不起呀。。。。
先简单的说下吧,百度提供了一个音乐搜索的api,你想百度请求类似于

http://box.zhangmen.baidu.com/x?op=12&count=1&title=最佳损友$$陈奕迅$$$$

的地址,百度会给你返回一段xml,如下所示

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<result>
<count>1</count>
<url>
<encode>
<![CDATA[
http://zhangmenshiting.baidu.com/data2/music/12762845/YmRqamdua21fn6NndK6ap5WXcJlrmG1xlJhobWibmGpjk5ZtmWiZcWRjZ5lqbGyelGKWlZtubGljZ5lka2uanWSXY1qin5t1YWBmZW5ocGlhaWdnbGtqbzE$
]]>
</encode>
<decode>
<![CDATA[
12762845.mp3?xcode=e6b69cf593ea22ac9d2b9314e565fc0caf85125f065ce3e0&mid=0.31929107437537
]]>
</decode>
<type>8</type>
<lrcid>2829</lrcid>
<flag>1</flag>
</url>
<durl>
<encode>
<![CDATA[
http://zhangmenshiting2.baidu.com/data2/music/7345405/aGVnaWlmbGaeomZzrZmmnJZvmGqXbHCbl2dsZ5qXaWqSlWpsmmdrb2mXamxpbXCclGNsmW2ba25mYmxtapmZcWqTWaGemnRoX2VkbWdvaGhoZmZramluOA$$
]]>
</encode>
<decode>
<![CDATA[
7345405.mp3?xcode=e6b69cf593ea22ac78e1478e78479dc19e8e4650995cb99a&mid=0.31929107437537
]]>
</decode>
<type>8</type>
<lrcid>2829</lrcid>
<flag>1</flag>
</durl>
<p2p>
<hash>f98b6772aa97966550ec80617879becee0233bf4</hash>
<url>
<![CDATA[ ]]>
</url>
<type>mp3</type>
<size>3778335</size>
<bitrate>128</bitrate>
</p2p>
</result>

简单的说明下,由于我们要做的只是获取到歌曲的lrc歌词地址,所以有用的只有2829这个标签。
而encode和decode里面的拼接起来就是mp3的下载地址,如本例的

http://zhangmenshiting.baidu.com/data2/music/12762845/YmRqamdua21fn6NndK6ap5WXcJlrmG1xlJhobWibmGpjk5ZtmWiZcWRjZ5lqbGyelGKWlZtubGljZ5lka2uanWSXY1qin5t1YWBmZW5ocGlhaWdnbGtqbzE$12762845.mp3?xcode=e6b69cf593ea22ac9d2b9314e565fc0caf85125f065ce3e0&mid=0.31929107437537

就是下载地址,不过音质太差,有时间在研究下这个。
继续说歌词,注意lrcid标签里面的2829
http://box.zhangmen.baidu.com/bdlrc/ 这个是百度lrc歌词存放地址,
然后本例的歌词地址是http://box.zhangmen.baidu.com/bdlrc/28/2829.lrc
看到了吧,歌词地址后面的两个数字的计算方法是在lrcid除以100所获得的整数,就是第一个数字,然后第二个数字就是lrcid,然后后面加上后缀.lrc就搞定了
获得lrc地址之后就简单了,只要请求该地址,然后将获取到的内容写入文件就ok了。
好了,大概就是这样,下面是代码

import os
import os.path
import re
import eyed3
import urllib2
import urllib
from urllib import urlencode
import sys 

import os
reload(sys) 
sys.setdefaultencoding('utf8')

music_path = r"E:\music"
lrc_path = r"e:\lrc"

os.remove('nolrc.txt')
os.remove('lrcxml.txt')

the_file = open('lrcxml.txt','a')
nolrc_file = open('nolrc.txt','a')

for root,dirs,files in os.walk(music_path):
  for filepath in files:
    the_path = os.path.join(root,filepath)
    if (the_path.find("mp3") != -1):
      print the_path
      the_music = eyed3.load(the_path)
      the_teg = the_music.tag._getAlbum()
      the_artist = the_music.tag._getArtist()
      the_title = the_music.tag._getTitle()
      # print the_teg
      # print the_title
      # print the_artist
      b = the_title.replace(' ','+')
      # print b
      a = the_artist.replace(' ','+')
      #print urlencode(str(b))
      if isinstance(a,unicode):
        a = a.encode('utf8')
      song_url = "http://box.zhangmen.baidu.com/x?op=12&count=1&title="+b+"$$"+a+"$$$$ "
     
      the_file.write(song_url+'\n')
      page = urllib2.urlopen(song_url).read()
      print page
      theid = 0
      
      lrcid = re.compile('<lrcid>(.*?)</lrcid>',re.S).findall(page)
      have_lrc = True
      if lrcid != []:
        theid = lrcid[0]
        
      else:
        nolrc_file.write(the_title+'\n')
        have_lrc = False
      print theid
      
      
      if have_lrc:
        firstid = int(theid)/100
        lrcurl = "http://box.zhangmen.baidu.com/bdlrc/"+str(firstid)+"/"+theid+".lrc"
        print lrcurl
        lrc = urllib2.urlopen(lrcurl).read()
        if(lrc.find('html')== -1):
          lrcfile = open(lrc_path+"\\"+the_title+".lrc",'w')
          lrcfile.writelines(lrc)
          lrcfile.close()
        else:
          nolrc_file.write(the_title+'\n')
        
the_file.close()
nolrc_file.close()
print "end!"

有用第一步请求所获取到底是xml格式的,所以本来想着解析xml来获取lrcid,但是在实现过程中遇到了各种问题,别的还容易,就在这一块儿浪费的时间最长,纠结未果之后,只能改用正则表达式来获取了。。。

使用python将歌词嵌入歌曲中
以前一直用的是Google Play Music来作为手机的音乐播放器,可是现在谷歌被墙的这么厉害的,从PC上传到Google Play的音乐在手机上面同步下来的话特麻烦,索性放弃之买了大名鼎鼎的Poweramp播放器,开始使用之后瞬间就被Poweramp强大的功能所吸引住了,不愧是安卓端的音乐播放器的王者!唯美的锁屏界面,强大的均衡器功能等等。唯一美中不足的就是歌词.如果要显示歌词的话必须安装第三方软件,或者是把歌词嵌入到音乐中。所以昨天下班之后就开始研究,所幸最后终于搞定了,先上下效果图

使用Python下载歌词并嵌入歌曲文件中的实现代码

可以看到,效果还是很不错的呢。
好了,废话不多说,下面上程序
首先,必须安装eyed3模块,还有,我所有的歌词都在E:\lrc这个路径中的

import threading
import time
import datetime
import re
import os
import eyed3
import sys
reload(sys)
sys.setdefaultencoding('utf8')


def getstr(i):
  if i <10:
    return "0"+str(i)
  else:
    return str(i)

musicpath=r'I:\music'

lrcpath=r'E:\lrc'



def deallrc(str):
  mystr=re.sub(r'\[\d\d:\d\d.\d\d\]','',str)
  mystr.replace('\n','')
  return mystr
  


def checklrcfile(path,timespan):
  file=open(path,'r')
  mylrcstr=''
  #print timespan
  for line in file.readlines(100):
    #errorlog(line)
    if line.find(timespan)>0:
      return deallrc(line)
    else:
      continue
  return ''

    
def getlrcstr(lrc):
  mylrcstr=''
  #print lrc
  for i in range(00,05):
    for j in range(00,59):
      for k in range(00,99):
        timespan=getstr(i)+":"+getstr(j)+"."+getstr(k)
        mylrcstr+=checklrcfile(lrc, timespan) 
      #print timespan
  return mylrcstr


def getlrc(musicname):
  musicname=u''.join(musicname)
  musicname=musicname.encode('gb2312')
  for root,dirs,files in os.walk(lrcpath):
    for filepath in files:
      the_path = os.path.join(root,filepath)
      if (the_path.find(musicname) != -1):
        print the_path
        return the_path

def errorlog(path):
  file=open(r'e:\nolrc.txt','a')
  if path is None:
    path=''
  path=path+'\n'
  file.write(path)
  file.close()

def writetag(themusic,lrcstr):
  music=eyed3.load(themusic)
  lrcstr=lrcstr.decode('utf8')
  lrcstr=u''.join(lrcstr)
  #lrcstr=unicode(lrcstr)
  music.tag.lyrics.set(lrcstr)
  music.tag.save()
  
  


def dealmusic(path):
  print path
  the_music = eyed3.load(path)
  the_teg = the_music.tag._getAlbum()
  the_artist = the_music.tag._getArtist()
  the_title = the_music.tag._getTitle()
  #print the_title
  
  try:
    lrc=getlrc(the_title)
    lrcstr=getlrcstr(lrc)
    writetag(path, lrcstr) 
  except:
    errorlog(path)
   
          

class writelrc(threading.Thread):
  def __init__(self,the_path):
    threading.Thread.__init__(self)
    self.thepath=the_path
  def run(self):
    dealmusic(self.thepath)


if __name__=='__main__':
  count=0
  threads=[]
  for root,dirs,files in os.walk(musicpath):
      for filepath in files:
        the_path = os.path.join(root,filepath)
        if (the_path.find("mp3") != -1):
          count+=1
          threads.append(writelrc(the_path))
          if count%10==0:
            for t in threads:
              t.start()
            for t in threads:
              t.join()
            threads=[]

  

好了,大概就是这样,大家有什么问题可以直接提出来,我会尽快回复的。

Python 相关文章推荐
python编程-将Python程序转化为可执行程序[整理]
Apr 09 Python
Python实现Linux下守护进程的编写方法
Aug 22 Python
使用Python的Flask框架构建大型Web应用程序的结构示例
Jun 04 Python
Python使用win32com模块实现数据库表结构自动生成word表格的方法
Jul 17 Python
python使用if语句实现一个猜拳游戏详解
Aug 27 Python
python小程序基于Jupyter实现天气查询的方法
Mar 27 Python
使用python检查yaml配置文件是否符合要求
Apr 09 Python
Python基于BeautifulSoup爬取京东商品信息
Jun 01 Python
python中的django是做什么的
Jul 31 Python
Python Selenium实现无可视化界面过程解析
Aug 25 Python
python中pdb模块实例用法
Jan 15 Python
python 提取html文本的方法
May 20 Python
Python设置Socket代理及实现远程摄像头控制的例子
Nov 13 #Python
深入解析Python中的urllib2模块
Nov 13 #Python
Python下的常用下载安装工具pip的安装方法
Nov 13 #Python
Python的Flask框架的简介和安装方法
Nov 13 #Python
Python编程入门之Hello World的三种实现方式
Nov 13 #Python
python编程开发之textwrap文本样式处理技巧
Nov 13 #Python
python编程开发之日期操作实例分析
Nov 13 #Python
You might like
利用php来自动调用不同服务器上的flash
2006/10/09 PHP
坏狼的PHP学习教程之第1天
2008/06/15 PHP
php权重计算方法代码分享
2014/01/09 PHP
thinkphp控制器调度使用示例
2014/02/24 PHP
使用配置类定义Codeigniter全局变量
2014/06/12 PHP
二级域名或跨域共享Cookies的实现方法
2008/08/07 Javascript
utf-8编码引起js输出中文乱码的解决办法
2010/06/23 Javascript
js FLASH幻灯片字符串中有连接符&的处理方法
2012/03/01 Javascript
jQuery 瀑布流 绝对定位布局(二)(延迟AJAX加载图片)
2012/05/23 Javascript
JS+CSS实现的蓝色table选项卡效果
2015/10/08 Javascript
Jquery uploadify上传插件使用详解
2016/01/13 Javascript
jquery zTree异步加载简单实例讲解
2016/02/25 Javascript
iScroll.js 使用方法参考
2016/05/16 Javascript
浅谈js中test()函数在正则中的使用
2016/08/19 Javascript
详解webpack异步加载业务模块
2017/06/23 Javascript
vue中如何创建多个ueditor实例教程
2017/11/14 Javascript
vue.js模仿京东省市区三级联动的选择组件实例代码
2017/11/22 Javascript
vue的状态管理模式vuex
2017/11/30 Javascript
Node.js静态服务器的实现方法
2018/02/28 Javascript
vue-infinite-loading2.0 中文文档详解
2018/04/08 Javascript
如何能分清npm cnpm npx nvm
2019/01/17 Javascript
如何解决.vue文件url引用文件的问题
2019/01/18 Javascript
微信小程序HTTP接口请求封装的实现
2019/02/21 Javascript
如何在Angular应用中创建包含组件方法示例
2019/03/23 Javascript
浅谈python中的getattr函数 hasattr函数
2016/06/14 Python
Python实现输出某区间范围内全部素数的方法
2018/05/02 Python
用python3教你任意Html主内容提取功能
2018/11/05 Python
基于python监控程序是否关闭
2020/01/14 Python
python爬虫模块URL管理器模块用法解析
2020/02/03 Python
关于Tensorflow 模型持久化详解
2020/02/12 Python
浅谈python中频繁的print到底能浪费多长时间
2020/02/21 Python
化学系大学生自荐信范文
2014/03/01 职场文书
党员自我剖析材料
2014/08/31 职场文书
教师见习报告范文
2014/11/03 职场文书
初中班级口号霸气押韵
2015/12/24 职场文书
如何使用python包中的sched事件调度器
2022/04/30 Python