【python爬虫】网易云歌单下载(scrapy+selenium)
我又滚回来更新了,这一次我们的目标是网易云音乐,想要通过输入歌单的链接,然后把整个歌单的歌曲都下载下来,说做就做,看看这一次有会遇见怎样的问题把。
需要注意的点:
- 这一次使用的框架仍然是scrapy,不同于上个框架的是这一回加上了selenium,我是蛮不想借助这个的,但是让工具发挥他最大的用处,这才是我们该做的
- VIP才能下载的音乐依然无法下载,现在还没有那个实力,只能下载歌单中不是vip的音乐
- 本文用于技术交流,如果侵犯版权立即删除,任何人不能用于商业用途
好的,那我们就开始吧,一开始我们先来分析一下网易云的歌单
这是这一次要分析的网址: https://music.163.com/#/playlist?id=61650863 ,顺便卖一波安利,这个歌单蛮不错的,喜欢纯音乐的朋友可以听听看。
首先我们要做的是获取这个歌单所有的歌曲的链接和名字,一开始觉得应该没有什么难度,
就算歌单是动态加载的,找起来应该也没有什么难度,但是事实是对现在的我确实是蛮难的。
右键网页源代码,搜索Rain after Summer(歌单第一首歌)发现果然是没有的
接下来便是在f12中查找,确实发现了歌单的信息,本来接下来就是
response = requests.get(url,headers=DEFAULT_REQUEST_HEADERS)
但即使发所有的request headers都加上了,这部分内容页面没能显示出来,要是有朋友知道这是怎么回事,希望可以多多指教。
但是我们是不能在一颗树上吊死的,既然这个方法行不通,那么就使别的方法,这次我是使用了selenium,但是用这个的时候也遇见一个坑了,在使用selenium之后本来以为所有问题都会迎刃而解的,但是发现仍然搜索不到任何有关歌单的信息,就纠结测试了许久之后,终于发现了问题的所在,一切都源于他
这是一个iframe,歌单所有的消息都在这个里面,但是selenium是没有办法自动加载这个里面的内容的,这就导致了我们怎样都看不见歌单的消息。成功得到歌单信息之后,那么就可以开始我们的下载大业了,下面就开始说代码了,里面遇见的问题再一边分析。
使用scrapy进行爬虫,scrapy框架目录结构如下:
在使用命令行创建scrapy之后,首先是在setting.py中将机器人协议改为false,设置请求头,还有将piplines和middlewares的注释取消掉,这一些上一个项目的时候已经介绍过了,不清楚的可以翻一下上一篇,接下来是items.py中的内容
准备工作就做到这里了,接下来就开始分析各个代码了
首先是start_music163.py中的内容,这是用来启动这个爬虫的。
然后是爬虫中的内容,在爬虫开启webdriver,并且设置在爬虫关闭的时候,关闭chrome浏览器,接着讲请求发送出去。
class MusicSpiderSpider(scrapy.Spider): name = 'music_spider' allowed_domains = ['music.163.com'] start_urls = ['http://music.163.com/'] # first_url = 'https://music.163.com/#/playlist?id=107391599' driver = webdriver.Chrome() driver.set_page_load_timeout(30) def __init__(self,gedan_url=None, *args, **kwargs): self.first_url = gedan_url #获得歌单链接之后,交给parse_catalog解析,但这里有开启中间件(middlewares.py) #所以请求会先被传去middlewares.py def start_requests(self): yield scrapy.http.Request(url=self.first_url,callback=self.parse_catalog) def closed(self, spider): self.driver.close()
这里是比较重要的一个点。打开middlewares.py,middlewares(中间件)在url请求发送出去之后,会先经过中间件,这个时候我们可以把它捕获,通过selenium的page_source获得更加完整的主页代码,注意看代码中的注释,spider.driver.switch_to.frame(‘g_iframe’)用于解决上面提及的webdriver没有办法自动加载iframe的问题
import scrapy class Music163DownloaderMiddleware(object): #rrequest的请求被传到这里,接下来使用webdriver进行解析,然后再把响应返回给parse_catalog def process_request(self, request, spider): ids = request.url.split('=')[-1] url = 'https://music.163.com/#/playlist?id=%s' % ids spider.driver.get(url) #注意:下面这一条代码很重要,因为webdriver无法显示出iframe中的东西 #所以需要使用switch_to.frame('g_iframe')来将隐藏的内容找出来 spider.driver.switch_to.frame('g_iframe') source = spider.driver.page_source return scrapy.http.HtmlResponse(url=url,body=source,encoding="utf-8",request=request)
之后我们回到爬虫中来对重新获得response进行数据清洗,通过xpath语法,成功将我们需要歌曲链接,歌曲名字和歌单名字全部传送给我们的piplines.py进行处理
#这里将歌单中每一首个的id和名字传到piplines.py进行处理 def parse_catalog(self, response): # print(response.text) songs_list = response.xpath('//table[@class="m-table "]/tbody/tr') big_title = response.xpath('//h2[@class="f-ff2 f-brk"]/text()').get() big_title = re.sub(r'[<>:"/\\|?*]', '', big_title) for song in songs_list: song_href = 'https://music.163.com/#'+song.xpath('.//a/@href').get() song_title = song.xpath('.//b/@title').get() song_ids = re.split('=',song_href)[-1] song_title = re.sub(r'[<>:"/\\|?*]', '', song_title) item = Music163Item(song_ids = song_ids,song_title = song_title,big_title=big_title) yield item
下载也是一个很难的点,因为歌曲链接是jingguoAES加密的,没有学过这方面知识的朋友可能看不懂要如何解密,博主也没能好好理解怎么破解,但是github上的大佬是无所不能的,总会有大佬能成功破解的。
这里要好好感谢这位大佬,顺便贴上github大佬的网址:https://github.com/Jack-Cherish/python-spider/tree/master/Netease ,这位大佬有很多爬虫的项目 可以学习一下。那么我们就借助这位大佬的帮助,继续完成我们这个项目。
以下是那位大佬的破解过程,感兴趣的朋友可以好好研究一下
#下面这一部分是github上的大佬写的,用于破解网易云音乐链接的命名方式,看起来应该是涉及到AES了 #这部分没有专业知识应该是看不懂的,有兴趣的朋友可以研究一下 #github大佬的网址是:https://github.com/Jack-Cherish/python-spider/tree/master/Netease #顺便一提 这位大佬有很多爬虫的项目 可以学习一下 class Encrypyed(): #解密算法 def __init__(self): self.modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7' self.nonce = '0CoJUm6Qyw8W8jud' self.pub_key = '010001' # 登录加密算法, 基于https://github.com/stkevintan/nw_musicbox脚本实现 def encrypted_request(self, text): text = json.dumps(text) sec_key = self.create_secret_key(16) enc_text = self.aes_encrypt(self.aes_encrypt(text, self.nonce), sec_key.decode('utf-8')) enc_sec_key = self.rsa_encrpt(sec_key, self.pub_key, self.modulus) data = {'params': enc_text, 'encSecKey': enc_sec_key} return data def aes_encrypt(self, text, secKey): pad = 16 - len(text) % 16 text = text + chr(pad) * pad encryptor = AES.new(secKey.encode('utf-8'), AES.MODE_CBC, b'0102030405060708') ciphertext = encryptor.encrypt(text.encode('utf-8')) ciphertext = base64.b64encode(ciphertext).decode('utf-8') return ciphertext def rsa_encrpt(self, text, pubKey, modulus): text = text[::-1] rs = pow(int(binascii.hexlify(text), 16), int(pubKey, 16), int(modulus, 16)) return format(rs, 'x').zfill(256) def create_secret_key(self, size): return binascii.hexlify(os.urandom(size))[:16] class Crawler(): def __init__(self, timeout=60, cookie_path='.'): self.session = requests.Session() self.session.headers.update(DEFAULT_REQUEST_HEADERS) self.session.cookies = cookiejar.LWPCookieJar(cookie_path) self.download_session = requests.Session() self.timeout = timeout self.ep = Encrypyed() def post_request(self, url, params): data = self.ep.encrypted_request(params) resp = self.session.post(url, data=data, timeout=self.timeout) result = resp.json() # print(resp.url) if result['code'] != 200: click.echo('post_request error') else: return result
结果处理之后,我们得到了真正的下载链接,那么就可以开始下载了。这里利用requests.session进行下载,这种下载方式也可以用于下载视频,非常建议朋友们学习一下,这里附上文档http://docs.python-requests.org/zh_CN/latest/user/advanced.html
class Music163Pipeline(object): def process_item(self, item, spider): #下载路径 path = './' gedang_name = os.path.join(path, item['big_title']) if not os.path.exists(gedang_name): os.mkdir(gedang_name) song_id = item['song_ids'] song_title = item['song_title'] #将每一首歌的id进行解码,获得下载的url链接 csrf = '' bit_rate = 320000 url = 'http://music.163.com/weapi/song/enhance/player/url?csrf_token=' params = {'ids': [song_id], 'br': bit_rate, 'csrf_token': csrf} crawl = Crawler() result = crawl.post_request(url, params) result_url = result['data'][0]['url'] #获得下载的url之后,便可以开始真正下载了 response = requests.session() resp = response.get(result_url,stream=True) with open(gedang_name+r'\\'+song_title+'.mp3','wb') as fp: for chunk in resp.iter_content(chunk_size=1024): if chunk: fp.write(chunk) return item
写到这里就大功告成了,接下来就是运行爬虫,等待结果了
大功告成,接下来我们就开始欣赏我们的音乐把,再次安利,这个歌单真的蛮不错的,喜欢纯音乐的朋友不要错过哦。我的分享就到这里了,要是大家能从里面收获到一点点,那对我来说便是极好了,我会把代码发到GitHub上,有兴趣的同学可以下载来研究一下!谢谢大家!
GitHub地址:https://github.com/weakmaple/music_163
- 【Python3爬虫】网易云音乐歌单下载
- Python3网络爬虫:Scrapy入门之使用ImagesPipline下载图片
- [Python爬虫] Selenium+Phantomjs动态获取CSDN下载资源信息和评论
- [Python爬虫] Selenium+Phantomjs动态获取CSDN下载资源信息和评论
- python爬虫框架scrapy学习图片下载
- python爬虫三:获取一个网易用户的所有图片(selenium+phantomjs)
- Python爬虫框架scrapy实现的文件下载功能示例
- Python 利用scrapy爬虫通过短短50行代码下载整站短视频
- Python爬虫scrapy框架爬取动态网站——scrapy与selenium结合爬取数据
- [Python爬虫]Scrapy框架爬取网易国内新闻
- 第三百五十节,Python分布式爬虫打造搜索引擎Scrapy精讲—selenium模块是一个python操作浏览器软件的一个模块,可以实现js动态网页请求
- 第三百五十一节,Python分布式爬虫打造搜索引擎Scrapy精讲—将selenium操作谷歌浏览器集成到scrapy中
- python+selenium+scrapy搭建简单爬虫
- [Python爬虫]Scrapy配合Selenium和PhantomJS爬取动态网页
- python+scrapy+selenium爬虫
- python 爬虫爬取下载网易云音乐歌单的歌曲(需要使用JS的加密方法得出params去获取下载地址)
- 【Python爬虫】Python+Selenium爬取百度圣卡/网易白金卡手机靓号
- Scrapy:Python实现scrapy框架爬虫两个网址下载网页内容信息——Jason niu
- python爬虫实战:利用scrapy,短短50行代码下载整站短视频
- Python3之爬虫selenium+chromedriver资源下载及“Message: 'chromedriver' executable needs to be in PATH.处理