selenium + phantomjs 爬取落网音乐
题记:
作为一个业余程序猿,最大的爱好就是电影和音乐了,听音乐当然要来点有档次的。落网的音乐的逼格有点高,一听听了10年。学习python一久了,于是想用python技术把落网的音乐爬下来随便听。
目的:
将每一期的落网音乐下载到电脑上。
=====================================================================================
版本一:
刚开始,学习了爬虫技术中的urllib,urllib2,httplib,然后学习了用requests + beautifulsoup获取数据(python理念:能简单为啥还要复杂)。
于是,就有了这个版本。
图1:
图2:
图3:
缺点:
1、从html元素查找title,再从request请求查看每一首音乐的url,这个半手动的违背了自动下载的初衷。
2、这个音乐url是规律的命名,如果不规律的话,便不能用了。
3、单线程下载,速度慢。
需要改进的地方:
1、音乐url应能自动在网页里搜索,而不需要手动查看request请求的header。
2、使用多线程。提高下载速度。
=================================================================
版本二:
分析:
1、打开落网每一期音乐的页面,查看源代码中,不能看到音乐的url,那判定该音乐是由js发起的请求。
2、要查看web页面中js发起的请求时,用requests模块只能获取静态的url,如果是动态的就没办法了。
3、通过搜索查阅,找到一款神器,selenium + phantomjs。
selenium是web自动化测试包,测试直接运行在浏览器中,就像真正的用户在操作一样,详见官网 http://www.seleniumhq.org。
phantomjs是基于webkit的javascript API,可以编译解释执行JavaScript代码。详见:官网 http://phantomjs.org。
webdriver api 见 http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webdriver。
4、Time fly,just do it。
在分析过程中,开始一直是requests模块的思维,由于落网的js是压缩过的,想到解压js,再查找相关的dom元素,再进行webElement的click提交,查看请求,但是这种方法一直没有结果。用了chrome 及 opera 的开发者工具,仍然无果。
换个思路,用了firefox的firebug试试。打开页面后,发现这个东西:
看了看内容,这就是js对象呀。再仔细查看,找到了这个:
哎哟,这不就是我要找的东西么,真是破铁鞋无觅处、得来全不费工夫呀。。。
但是,如果通过代码得到这个东西呢,一直没想到好的办法(业余菜鸟,对http请求了解太少)。
偶然看到这篇帖子:http://blog.csdn.net/pushiqiang/article/details/51290509
里面有一句代码得到启发:
这是返回js变量,那我需要的代码变量应用就是firebug里的luooPlayer了。
测试:
得到结果:
终于,主要的内容搞定。那接下来就是download每一期了,再加上多线程,就能下载了。
代码:
1 #coding:utf-8 2 ''' 3 Auth:daivlin 4 Date:2016-12-22 5 ''' 6 7 import os 8 import time 9 import urllib 10 import threading 11 from selenium import webdriver 12 13 class Luoo(object): 14 def __init__(self,issue): 15 ''' init ,参数为期数 ''' 16 self.issue_url = r"http://www.luoo.net/music/" + "%03d"%issue 17 driver = webdriver.PhantomJS() 18 driver.get(self.issue_url) 19 20 #每期名称如: VOL666 欢迎来到巴黎 21 self.issue_name = "VOL." + "%03d"%issue + " " + driver.title 22 luooPlayer = driver.execute_script("return luooPlayer") #读取js变量 23 24 #音乐列表为元组:(name,url) 25 self.music_list = [] 26 var = 1 27 for i in luooPlayer["playlist"]: 28 self.music_list.append(("%02d"%var,i["mp3"])) 29 var += 1 30 driver.quit() 31 32 def get_issue_name(self): 33 ''' 获取期刊号 ''' 34 return self.issue_name 35 36 def get_music_list(self): 37 ''' 获取音乐列表 ''' 38 return self.music_list 39 40 class DownloadThread(threading.Thread): 41 ''' 下载线程''' 42 def __init__(self,dirname,name,url): 43 super(DownloadThread,self).__init__() 44 self.dirname = dirname 45 self.name = name 46 self.url = url 47 48 def run(self): 49 ''' 下载音乐 ''' 50 ABSPATH = os.path.dirname(os.path.realpath(__file__)) 51 DOWNDIR = os.path.join(os.path.join(ABSPATH,"Luoo"),"%s"%self.dirname) 52 MUSICPATH = os.path.join(DOWNDIR,"%s.mp3"%self.name) 53 try: 54 os.mkdir(DOWNDIR) 55 except: 56 pass 57 if not os.path.exists(MUSICPATH): 58 urllib.urlretrieve(self.url, MUSICPATH) 59 print "%s.mp3 was downloaded"%self.name 60 61 for i in range(867,888): 62 r = Luoo(i) 63 name = r.get_issue_name() 64 tds = [] 65 for j in r.get_music_list(): 66 tds.append(DownloadThread(name,j[0],j[1])) 67 print "start download %s"%name 68 for td in tds: 69 td.start() 70 for tj in tds: 71 tj.join() 72 print "%s download complate"%name 73 print "=========================" 74 75 print "All have downloaded"
下载效果:
待改进的地方:
1、因为编码问题报错,文件名称用序号代替,需改为真实音乐名称。
==============================================================================
webdriver执行js代码,得到返回的值代码如下:
jscode = ''' var img_src = $("img.vol-cover"); return img_src.attr("src"); ''' img_cover = driver.execute_script(jscode)
==============================================================================
爬虫只供参考
做个厚道的程序猿
别增加人家的服务器压力
==============================================================================
人生苦短,我用python!