一直想把喜欢的歌手的专辑全都归类并下载下来,由于那专辑数量实在太多了,再加上最近开始学习python,就想着何不用python写个脚本把下载过程自动化呢?所以就花了点时间写了这么个东西,分享给有需要的人。:)

写这个东西,一开始并没有想到抓取过于频繁、时间过长会出现验证码,由于验证码的问题试了几种方式都无法得到很好的解决,于是加上了生成下载清单这一步,
加这一步的时候,一开始是把最终下载地址存储起来,结果发现,下载地址居然会过期,没办法最后只有将下载页面地址存储下来,使用下载命令的时候,再去下载
页面获取最终下载地址。

这段脚本使用了两个开源的模块,gevent和BeautifulSoup。

updated-------------------------------------------------------------------------------------------

已解除验证码限制,若出现验证码,则会从验证码页面中提取出所需cookie并重新发起请求。

   #coding=utf-8

    import urllib,urllib2,re,os,json,gevent,traceback
from BeautifulSoup import BeautifulSoup
from gevent import monkey monkey.patch_all() rootUrl='http://music.baidu.com'
artistId=2825 #想批量下载并归类你喜欢的歌手的所有专辑?那就把这里替换成该歌手在百度音乐的Id吧,例如:http://music.baidu.com/artist/2825
pagesize=10
savePath='G:\\crawl\\david bowie\\' #改成你想存储的文件夹
listDir='_____downlist\\'
handleCount=0
BAIDUVERIFY='' def crawlList():
artistUrl=rootUrl+'/artist/'+str(artistId)
homeHtml=request(artistUrl)
soup=BeautifulSoup(homeHtml)
try:
pagecount=len(soup.findAll("div",{"class":"page-inner"})[1].findAll(text=re.compile(r'\d+')))
except:
print traceback.print_exc()
print homeHtml
return
jobs=[]
listPath=savePath+listDir
if not os.path.exists(listPath):
os.mkdir(listPath)
for i in range(pagecount):
jobs.append(gevent.spawn(crawlPage,i))
gevent.joinall(jobs) def request(url):
global BAIDUVERIFY
req=urllib2.Request(url)
if BAIDUVERIFY!='':
req.add_header('Cookie','BAIDUVERIFY='+BAIDUVERIFY+';')
resp=urllib2.urlopen(req)
html= resp.read()
verify=getBaiduVerify(html)
if verify!='':
print u'成功提取验证码并重新发起请求'
BAIDUVERIFY=verify
return request(url)
return html def getBaiduVerify(html):
vcode=re.search(r'name=\"vcode\" value=\"(.*?)\"' , html, re.I)
id=re.search(r'name=\"id\" value=\"(.*?)\"' , html, re.I)
di=re.search(r'name=\"di\" value=\"(.*?)\"' , html, re.I)
if vcode and id and di:
return vcode.group(1)+':'+id.group(1)+':'+di.group(1)
return '' def crawlPage(page):
start=page*pagesize
albumListUrl='http://music.baidu.com/data/user/getalbums?start=%d&ting_uid=%d&order=time' % (start,artistId)
print albumListUrl
albumListHtml=json.loads(request(albumListUrl))["data"]["html"]
albumListSoup=BeautifulSoup(albumListHtml)
covers=albumListSoup.findAll('a',{'class':'cover'})
pagePath=savePath+listDir+str(page)+'\\'
if not os.path.exists(pagePath):
os.mkdir(pagePath)
for cover in covers:
try:
crawlAlbum(pagePath,rootUrl+cover['href'],cover['title'])
except:
print traceback.print_exc() def crawlAlbum(pagePath,albumUrl,title):
print albumUrl,title
albumHtml=request(albumUrl)
albumSoup=BeautifulSoup(albumHtml)
musicWraps=albumSoup.findAll('span',{'class':'song-title '})
title=re.subn(r'\\|\/|:|\*|\?|\"|\<|\>|\|','',title)[0]
path=savePath+title+'\\'
albumListPath=pagePath+title+'.txt'
albumFile=open(albumListPath,'w')
for wrap in musicWraps:
link=wrap.find('a')
try:
musicPage=rootUrl+link['href']
albumFile.write('%s\t%s\t%s\n' % (musicPage,link['title'],path)) #真实下载地址会过期,这里保存下载页面
except:
print traceback.print_exc()
albumFile.close() def crawlDownloadUrl(musicPage):
downPage=musicPage+'/download'
downHtml=request(downPage)
downUrl=re.search('http://[^ ]*xcode.[a-z0-9]*' , downHtml, re.M).group()
return downUrl def downList():
listPath=savePath+listDir
jobs=[]
for pageDir in os.listdir(listPath):
jobs.append(gevent.spawn(downPage,listPath+pageDir))
gevent.joinall(jobs) def downPage(pagePath):
for filename in os.listdir(pagePath):
filePath=pagePath+'\\'+filename
albumFile=open(filePath,'r')
try:
for args in albumFile.readlines():
arrArgs=args.split('\t')
downMusic(arrArgs[0],arrArgs[1],arrArgs[2].replace('\n',''))
except:
print traceback.print_exc()
finally:
albumFile.close() def downMusic(musicPage,title,path):
global handleCount
if not os.path.exists(path):
os.mkdir(path)
handleCount+=1
print handleCount,musicPage,title,path
filename=path+re.subn(r'\\|\/|:|\*|\?|\"|\<|\>|\|','',title)[0]+'.mp3'
if os.path.isfile(filename):
return
downUrl=crawlDownloadUrl(musicPage)
try:
urllib.urlretrieve(downUrl,filename)
except:
print traceback.print_exc()
os.remove(filename) if __name__=='__main__':
print u'命令:\n\tlist\t生成下载清单\n\tdown\t开始下载\n\texit\t退出'
cmd=raw_input('>>>')
while cmd!='exit':
if cmd=='list':
crawlList()
print u'已生成下载清单'
elif cmd=='down':
downList()
print u'下载完成'
else:
print 'unknow cmd'
cmd=raw_input('>>>')

MusiCode 批量下载指定歌手的所有专辑(已解除验证码限制)的更多相关文章

  1. Linux运维之批量下载指定网站的100个图片文件,并找出大于200KB的文件

    题目为:  有一百个图片文件,它们的地址都是http://down.fengge.com/img/1.pnghttp://down.fengge.com/img/2.png…一直到http://dow ...

  2. 批量下载网站图片的Python实用小工具

    定位 本文适合于熟悉Python编程且对互联网高清图片饶有兴趣的筒鞋.读完本文后,将学会如何使用Python库批量并发地抓取网页和下载图片资源.只要懂得如何安装Python库以及运行Python程序, ...

  3. 获取Google音乐的具体信息(方便对Google音乐批量下载)

    Google音乐都是正版音乐, 不像百度所有都是盗链, 并且死链也多. 但有一个麻烦就是要下载Google音乐的时候得一个一个的点击下载链接, 进入下载页面再点"下载", 才干下载 ...

  4. KRPano资源分析工具使用说明(KRPano XML/JS解密 切片图批量下载 球面图还原 加密混淆JS还原美化)

    软件交流群:571171251(软件免费版本在群内提供) krpano技术交流群:551278936(软件免费版本在群内提供) 最新博客地址:blog.turenlong.com 限时下载地址:htt ...

  5. Java实现批量下载《神秘的程序员》漫画

    上周看了西乔的博客“西乔的九卦”.<神秘的程序员们>系列漫画感觉很喜欢,很搞笑.这些漫画经常出现在CSDN“程序员”杂志末页的,以前也看过一些. 后来就想下载下来,但是一张一张的点击右键“ ...

  6. C#实现图标批量下载

    本文略微有些长,花了好几晚时间编辑修改,若在措辞排版上有问题,请谅解.本文共分为四篇,下面是主要内容,也是软件开发基本流程. 阶段 描述 需求分析 主要描述实现本程序的目的及对需求进行分析,即为什么要 ...

  7. 在ASP.NET中实现压缩多个文件为.zip文件,实现批量下载功能 (转载并优化处理篇)

    转自:http://blog.csdn.net/yanlele424/article/details/6895986 这段时间一直在做一个网站,其中遇到了一个问题,就是在服务器端压缩多个服务器端的文件 ...

  8. Lrc歌词批量下载助手 MP3歌词批量下载助手

    Lrc歌词批量下载助手  MP3歌词批量下载助手   易歌词的服务器已经挂掉,各个主流播放器已不提供明确的下载Lrc服务,当上G的MP3文件遇上苦逼的播放器,二缺就诞生了!本软件就是在这种背景下诞生的 ...

  9. Python 爬取qqmusic音乐url并批量下载

    qqmusic上的音乐还是不少的,有些时候想要下载好听的音乐,但有每次在网页下载都是烦人的登录什么的.于是,来了个qqmusic的爬虫. 至少我觉得for循环爬虫,最核心的应该就是找到待爬元素所在ur ...

随机推荐

  1. zookeeper入门知识

    ZooKeeper 是什么? ZooKeeper 顾名思义 动物园管理员,他是拿来管大象(Hadoop) . 蜜蜂(Hive) .小猪(Pig)  的管理员, Apache Hbase和 Apache ...

  2. ios随机数

    ios 随机数生成 字数612 阅读3037 评论1 喜欢15 最近一直使用随机数,为了以后方便查阅,总结一下: 在C中提供了rand().srand().random().arc4random()几 ...

  3. Python第三方库安装技巧

    pytho下有三种安装第三方库方法: 1.通过easy_install安装 2.通过Pip安装 前面两种,由于受国内部门网站原因,如果安装失败,可采用接下来的第三种方法 3.在指定网站下载安装 第三方 ...

  4. rm删除文件时排除特定文件

    删除当前目录下所有的*.txt文件,但除了test.txt文件: rm `ls *.txt | grep -v test.txt` 或者 rm `ls *.txt | egrep -v test.tx ...

  5. spark开发

    1. 主要参考资料http://spark.incubator.apache.org/docs/latest/scala-programming-guide.htmlhttp://www.eecs.b ...

  6. JDK1.5与1.6在Override上的区别

    @Override是JDK5 就已经有了,但有个小小的Bug,就是不支持对接口的实现,认为这不是Override 而JDK6 修正了这个Bug,无论是对父类的方法覆盖还是对接口的实现都可以加上@Ove ...

  7. Codeforces Round #364 (Div. 2) E. Connecting Universities

    E. Connecting Universities time limit per test 3 seconds memory limit per test 256 megabytes input s ...

  8. LeetCode OJ 257. Binary Tree Paths

    Given a binary tree, return all root-to-leaf paths. For example, given the following binary tree: 1 ...

  9. asp.net html table to DataTable

    添加引用 http://htmlagilitypack.codeplex.com/downloads/get/437941 protected void Export(string content,s ...

  10. mysql innobackupex备份工具

    先简单介绍一下这个工具:innobackupexinnobackupex比xtarbackup有更强的功能,它整合了xtrabackup和其他的一些功能,他不但可以全量备份/恢复,还可以基于时间的增量 ...