基于python的网易云音乐分析

Dreamlover

发布日期: 2019-04-29 21:40:48 浏览量: 656
评分:
star star star star star star star star star star
*转载请注明来自write-bug.com
  • MacOS Sierra 10.12.1

  • Python 2.7

  • selenium 3.4.3

  • phantomjs

前言

发现自己有时候比挖掘别人来的更加有意义,自己到底喜欢谁的歌,自己真的知道么?习惯不会骗你

搭建爬虫环境

1.安装selenium

  1. pip install selenium
  2. # anaconda环境的可用conda install selenium
  3. # 网速不好的可用到https://pypi.python.org/pypi/selenium下载压缩包,解压后使用python setup.py install

2.安装Phantomjs

2.1 Mac版本

  1. 步骤一下载包:去这里下载对应版本http://phantomjs.org/download.html
  2. 步骤二解压:双击就行,用unzip这都无所谓
  3. 步骤三切入路径:cd ~/Downloads/phantomjs-2.1.1-macosx/bin # 我下的路径的路径是download,版本不一,注意修改
  4. 步骤四:chmod +x phantomjs
  5. 步骤五: 配置环境,因为我装的的zsh,所以文件需要修改的是~/.zshrc这个文件,加上这句话export PATH="/Users/mrlevo/Downloads/phantomjs-2.1.1-macosx/bin/:$PATH",然后source ~/.zshrc 即可生效(没用zsh的同学,直接修改的文件时~/.bash_profile,添加内容和上述一致)
  6. 查看是否生效:phantomjs -v # 有信息如 2.1.1 则生效

mac若遇到问题请参考PhantomJS 安装

2.2 Win版本

  1. 官网http://phantomjs.org/下载PhantomJS解压后如下图所示:

调用时可能会报错“Unable to start phantomjs with ghostdriver”如图:

此时可以设置下Phantomjs的路径,同时如果你配置了Scripts目录环境变量,可以解压Phantomjs到该文件夹下。可参考Selenium with GhostDriver in Python on Windows - stackoverflow,整个win安装过程可参考在Windows下安装PIP+Phantomjs+Selenium],Mac和Linux/Ubuntu 下可参考[解决:Ubuntu(MacOS)+phantomjs+python的部署问题

3. 测试安装是否成功

  1. # 进入python环境后执行如下操作
  2. # win下操作
  3. >>> from selenium import webdriver # pip install selenium
  4. >>> driver_detail = webdriver.PhantomJS(executable_path="F:\Python\phantomjs-1.9.1-windows\phantomjs.exe")
  5. >>> driver_detail.get('https://www.baidu.com')
  6. >>> news = driver_detail.find_element_by_xpath("//div[@id='u1']/a")
  7. >>> print news.text
  8. 新闻
  9. >>> driver_detail.quit() # 记得关闭,不然耗费内存
  10. ------------------------------------------------------------------------
  11. # mac下操作
  12. >>> from selenium import webdriver # pip install selenium
  13. >>> driver_detail = webdriver.PhantomJS()
  14. >>> driver_detail.get('https://www.baidu.com')
  15. >>> news = driver_detail.find_element_by_xpath("//div[@id='u1']/a")
  16. >>> print news.text
  17. 新闻
  18. >>> driver_detail.quit() # 记得关闭,不然耗费内存

爬取动态数据

获取自己的id号,这个可以自己登陆自己的网易云音乐后获得,就是id=后面那个值

构造爬取的id,因为我发现,每个人的id只要被获取到,他的歌单都是公开的!!!这就节省了自动登录的一步,而且,我还有个大胆的想法,哈哈哈,我还要搞个大新闻!这次先不说~

墙裂推荐先阅读该博客掌握获取元素方法:Python爬虫 Selenium实现自动登录163邮箱和Locating Elements介绍

  1. # -*- coding: utf-8 -*-
  2. import traceback
  3. from selenium import webdriver
  4. import selenium.webdriver.support.ui as ui
  5. from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
  6. import time
  7. import random
  8. # 存储为文本的子函数
  9. def write2txt(data,path):
  10. f = open(path,"a")
  11. f.write(data)
  12. f.write("\n")
  13. f.close()
  14. # 获取该id喜欢音乐的列表
  15. def catchSongs(url_id,url):
  16. user = url_id.split('=')[-1].strip()
  17. print 'excute user:',user
  18. driver = webdriver.PhantomJS()#,executable_path='/Users/mrlevo/phantomjs-2.1.1-macosx/bin/phantomjs') # 注意填上路径
  19. driver.get(url)
  20. driver.switch_to_frame('g_iframe') # 网易云的音乐元素都放在框架内!!!!先切换框架
  21. try:
  22. wait = ui.WebDriverWait(driver,15)
  23. wait.until(lambda driver: driver.find_element_by_xpath('//*[@class="j-flag"]/table/tbody')) # 等待元素渲染出来
  24. try:
  25. song_key = 1
  26. wrong_time = 0
  27. while wrong_time < 5: # 不断获取歌信息,假定5次获取不到值,就判无值可获取,跳出循环
  28. try:
  29. songs = driver.find_elements_by_xpath('//*[@class="j-flag"]/table/tbody/tr[%s]'%song_key)
  30. info_ = songs[0].text.strip().split("\n")
  31. if len(info_) == 5:
  32. info_.insert(2,'None') # 没有MV选项的进行插入None
  33. new_line = '%s|'%user+'|'.join(info_)
  34. song_key +=1
  35. #new_line = "%s|%s|%s|%s|%s|%s|%s"%(user,info_[0],info_[1],info_[2],info_[3],info_[4],info_[5])
  36. print new_line
  37. write2txt(new_line.encode('utf-8'),user) # mac写入文件需要改变字符,以id命名的文件,存储在执行脚本的当前路径下,在win下请去掉编.endcode('utf-8')
  38. except Exception as ex:
  39. wrong_time +=1
  40. # print ex
  41. except Exception as ex:
  42. pass
  43. except Exception as ex:
  44. traceback.print_exc()
  45. finally:
  46. driver.quit()
  47. # 获取id所喜爱的音乐的url
  48. def catchPlaylist(url):
  49. driver = webdriver.PhantomJS()#,executable_path='/Users/mrlevo/phantomjs-2.1.1-macosx/bin/phantomjs') # 注意填上路径
  50. driver.get(url)
  51. driver.switch_to_frame('g_iframe') # 网易云的音乐元素都放在框架内!!!!先切换框架
  52. try:
  53. wait = ui.WebDriverWait(driver,15)
  54. wait.until(lambda driver: driver.find_element_by_xpath('//*[@class="m-cvrlst f-cb"]/li[1]/div/a')) # 根据xpath获取元素
  55. urls = driver.find_elements_by_xpath('//*[@class="m-cvrlst f-cb"]/li[1]/div/a')
  56. favourite_url = urls[0].get_attribute("href")
  57. except Exception as ex:
  58. traceback.print_exc()
  59. finally:
  60. driver.quit()
  61. # print favourite_url
  62. return favourite_url
  63. if __name__ == '__main__':
  64. for url in ['http://music.163.com/user/home?id=67259702']: # 这里把自己的id替换掉,想爬谁的歌单都可以,只要你有他的id
  65. time.sleep(random.randint(2, 4)) # 随机休眠时间2~4秒
  66. url_playlist = catchPlaylist(url)
  67. time.sleep(random.randint(1, 2))
  68. catchSongs(url,url_playlist)

不出意外的话,你的执行脚本的目录下会产生一个以你的id命名的文件,里面打开应该是这样的

  1. 67259702|2|因为了解|None|04:08|汪苏泷|慢慢懂
  2. 67259702|3|潮鳴り|None|02:37|折戸伸治|CLANNAD ORIGINAL SOUNDTRACK
  3. 67259702|4|每个人都会|None|02:58|方大同|橙月 Orange Moon
  4. 67259702|5|Don't Cry (Original)|MV|04:44|Guns N' Roses|Greatest Hits
  5. 67259702|6|妖孽(Cover:蒋蒋)|None|02:58|醉影An|醉声梦影
  6. 67259702|7|好好说再见(Cover 陶喆 / 关诗敏)|None|04:06|锦零/疯疯|zero
  7. 67259702|8|好好说再见(cover陶喆)|None|03:34|AllenRock|WarmCovers ·早
  8. # 这边分别爬取的数据结构是: id|歌次序|歌名|是否有MV|时长|歌手|专辑

Show数据-ROUND1

接下来就是处理自己下好的自己的歌单了,为了方便起见,我在构造爬取代码的时候,已经构造的比较好了,这也就帮助大家减少了数据预处理的时间了,一般来说,数据不会那么干净的。

我只是做了最简单的歌手词云的例子,数据比较丰富的情况下,自己处理吧,想做什么统计都可以,或许以后我会补上可视化相关的一些例子

1. 自定义遮罩层版本

  1. # -*- coding: utf-8 -*-
  2. # 如果还不清楚词云怎么搞,请参考这里https://mp.weixin.qq.com/s/0Bw8QUo1YfWZR_Boeaxu_Q,或者自行百度,很简单的一个包
  3. import numpy as np
  4. import PIL.Image as Image
  5. from wordcloud import WordCloud, ImageColorGenerator
  6. import matplotlib.pyplot as plt
  7. # 统计词频
  8. # win的用户,把解码去掉即可,因为当时mac写入的文件有编码,所以读出来需要解码
  9. def statistics(lst):
  10. dic = {}
  11. for k in lst:
  12. if not k.decode('utf-8') in dic:dic[k.decode('utf-8')] = 0
  13. dic[k.decode('utf-8')] +=1
  14. return dic
  15. path = '67259702' # 自己路径自己搞定
  16. list_ = []
  17. with open(path,'r') as f:
  18. for line in f:
  19. list_.append(line.strip().split('|')[-2].strip())
  20. dict_ = statistics(list_)
  21. # the font from github: https://github.com/adobe-fonts
  22. font = r'SimHei.ttf'
  23. coloring = np.array(Image.open("screenshot.png")) # 遮罩层自己定义,可选自己的图片
  24. wc = WordCloud(background_color="white",
  25. collocations=False,
  26. font_path=font,
  27. width=1400,
  28. height=1400,
  29. margin=2,
  30. mask=np.array(Image.open("screenshot.png"))).generate_from_frequencies(dict_)
  31. # 这里采用了generate_from_frequencies(dict_)的方法,里面传入的值是{‘歌手1’:5,‘歌手2’:8,},分别是歌手及出现次数,其实和jieba分词
  32. # 之后使用generate(text)是一个效果,只是这里的text已经被jieba封装成字典了
  33. image_colors = ImageColorGenerator(np.array(Image.open("screenshot.png")))
  34. plt.imshow(wc.recolor(color_func=image_colors))
  35. plt.imshow(wc)
  36. plt.axis("off")
  37. plt.show()
  38. wc.to_file('mymusic2.png') # 把词云保存下来

2. 方块版本

  1. # -*- coding: utf-8 -*-
  2. # 稍微修改下参数,就是另一幅图,这是没有遮罩层的
  3. import numpy as np
  4. import PIL.Image as Image
  5. from wordcloud import WordCloud, ImageColorGenerator
  6. import matplotlib.pyplot as plt
  7. # 统计词频
  8. def statistics(lst):
  9. dic = {}
  10. for k in lst:
  11. if not k.decode('utf-8') in dic:dic[k.decode('utf-8')] = 0
  12. dic[k.decode('utf-8')] +=1
  13. return dic
  14. path = '67259702' # 自己路径自己搞定
  15. list_ = []
  16. with open(path,'r') as f:
  17. for line in f:
  18. list_.append(line.strip().split('|')[-2].strip())
  19. dict_ = statistics(list_)
  20. # the font from github: https://github.com/adobe-fonts
  21. font = r'SimHei.ttf'
  22. coloring = np.array(Image.open("screenshot.png"))
  23. wc = WordCloud(
  24. collocations=False,
  25. font_path=font,
  26. width=1400,
  27. height=1400,
  28. margin=2,
  29. ).generate_from_frequencies(dict_)
  30. # 这里采用了generate_from_frequencies(dict_)的方法,里面传入的值是{‘歌手1’:5,‘歌手2’:8,},分别是歌手及出现次数,其实和jieba分词
  31. # 之后使用generate(text)是一个效果,只是这里的text已经被jieba封装成字典了
  32. image_colors = ImageColorGenerator(np.array(Image.open("screenshot.png")))
  33. plt.imshow(wc)
  34. plt.axis("off")
  35. plt.show()
  36. wc.to_file('mymusic2.png') # 把词云保存下来

SHOW数据-ROUND2

刚看到个好玩的,迫不及待的试了下,这是关于语种翻译的API接口,阿里云买的,0.01=1000条,买买买,买来玩玩试试自己歌曲语种

  1. # -*- coding:utf-8 -*-
  2. # 调用的阿里云的API接口实现语种翻译
  3. # API官网:https://market.aliyun.com/products/57124001/cmapi010395.html?spm=5176.730005.0.0.UrR9bO#sku=yuncode439500000
  4. import urllib, urllib2, sys
  5. import ssl
  6. def Lang2Country(text):
  7. host = 'https://dm-12.data.aliyun.com'
  8. path = '/rest/160601/mt/detect.json'
  9. method = 'POST'
  10. appcode = 'xxxxx' # 购买后提供的appcode码
  11. querys = ''
  12. bodys = {}
  13. url = host + path
  14. bodys['q'] = text
  15. post_data = urllib.urlencode(bodys)
  16. request = urllib2.Request(url, post_data)
  17. request.add_header('Authorization', 'APPCODE ' + appcode)
  18. # 根据API的要求,定义相对应的Content-Type
  19. request.add_header('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
  20. ctx = ssl.create_default_context()
  21. ctx.check_hostname = False
  22. ctx.verify_mode = ssl.CERT_NONE
  23. response = urllib2.urlopen(request, context=ctx)
  24. content = response.read()
  25. if (content):
  26. # print(content)
  27. return content
  28. else:
  29. return None
  30. # 67259702|1|Claux - 水之畔(8lope Remix) (feat. 陶心瑶)|None|02:44|8lope|水之畔(feat. 陶心瑶) (8lope Remix)
  31. list_songs = []
  32. list_songwithsinger = []
  33. with open('67259702') as f: # 文件名写上次爬下来的
  34. for line in f:
  35. line_split = line.split('|')
  36. list_songs.append(line_split[2])
  37. list_songwithsinger.append(line_split[2]+line_split[5])
  38. # 调用接口进行语种识别
  39. dict_lang = {}
  40. for i in range(537):
  41. try:
  42. content = Lang2Country(list_songwithsinger[i])
  43. lag_ = json.loads(content)['data']['language']
  44. if lag_ not in dict_lang:
  45. dict_lang[lag_]=0
  46. dict_lang[lag_] +=1
  47. except:
  48. pass
  49. print dict_lang
  50. # {u'ru': 1, u'fr': 9, u'en': 111, u'zh': 259, u'pt': 21, u'ko': 8, u'de': 7, u'tr': 15, u'it': 47, u'id': 2, u'pl': 7, u'th': 1, u'nl': 10, u'ja': 17, u'es': 20}

ok,数据准备好了,接下来可视化就好了!这次我用Echarts,换个口味的就不用云词了,来个统计效果好看点的!

  1. # 进入该网页:http://echarts.baidu.com/demo.html#pie-simple
  2. # 然后把里面的内容替换掉就行
  3. option = {
  4. title : {
  5. text: '哈士奇说喵喜欢的音乐',
  6. x:'center'
  7. },
  8. tooltip : {
  9. trigger: 'item',
  10. formatter:'{b} : {c} ({d}%)'
  11. },
  12. legend: {
  13. orient: 'vertical',
  14. left: 'left',
  15. data:['中文','英文','俄语','法语','葡萄牙语','韩语','德语','土耳其语','意大利语']
  16. },
  17. series : [
  18. {
  19. name: '访问来源',
  20. type: 'pie',
  21. radius : '55%',
  22. center: ['50%', '60%'],
  23. itemStyle: {
  24. normal: {label:{
  25. show:true,
  26. formatter:'{b} : {c} ({d}%)'
  27. },
  28. }},
  29. data:[
  30. {value:259, name:'中文'},
  31. {value:111,name:'英文'},
  32. {value:1, name:'俄语'},
  33. {value:9, name:'法语'},
  34. {value:21, name:'葡萄牙语'},
  35. {value:8, name:'韩语'},
  36. {value:7, name:'德语'},
  37. {value:15, name:'土耳其语'},
  38. {value:47, name:'意大利语'},
  39. {value:2, name:'印尼语'},
  40. {value:7, name:'波兰语'},
  41. {value:1, name:'泰语'},
  42. {value:10, name:'荷兰语'},
  43. {value:17, name:'日语'},
  44. {value:20, name:'西班牙语'},
  45. ],
  46. }
  47. ]
  48. };

Pay Attention

  • 这里遇到的最大问题,就是网易云的网页竟然还iframe框来做!!!不切入那个内联框架连phantomjs都无能为力!!这是最值得注意的一点,即使你找对了元素,也可能获取不到值!

  • 如果是win的计算机,在 driver = webdriver.PhantomJS()里面填上phantomjs.exe的路径,上面抓取数据的代码里面有两个需要引擎需要填写路径

  • 如果有打印出字段,但是记录的数据为0KB,那么是文件没有写进去,对于win的用户,把代码写入的部门,编码方式去掉即可

  • 有些win的小伙伴反应路径都加载对了,但是还是找不到exe,那么请在路径前面加r比如 executable_path=r"F:\Python\phantomjs-1.9.1-windows\phantomjs.exe"

结论

果然一下子就看出是上个世纪九十年代的人(:,还有就是,音乐不分国界,就是动感~

附录

对照表

上传的附件 cloud_download 基于python的网易云音乐爬取分析.zip ( 4.46mb, 1次下载 )
error_outline 下载需要10点积分

发送私信

花有重开日,人无再少年

17
文章数
21
评论数
最近文章
eject