网易云音乐上的所有!全部!随便爬!(Python爬虫&基于网易云音乐评论的用户推荐系统)(一) 您所在的位置:网站首页 酷狗评论最多的歌手 网易云音乐上的所有!全部!随便爬!(Python爬虫&基于网易云音乐评论的用户推荐系统)(一)

网易云音乐上的所有!全部!随便爬!(Python爬虫&基于网易云音乐评论的用户推荐系统)(一)

2023-07-14 11:35| 来源: 网络整理| 查看: 265

申明:本文纯属原创,有参考的地方都会在文中给出链接。如有转载,需征求本人同意。

一、目标网站介绍

网易云音乐是一款由网易开发的音乐产品,是网易杭州研究院的成果,依托专业音乐人、DJ、好友推荐及社交功能,在线音乐服务主打歌单、社交、大牌推荐和音乐指纹,以歌单、DJ节目、社交、地理位置为核心要素,主打发现和分享。

2017年11月17日,网易云用户突破4亿。知乎上有这样一个问题:你为什么用网易云。其中,有一条是这样说的:

成年人的生活里有太多无奈。 我之前把情绪和秘密写在QQ留言板里,被朋友们发现。 后来写在人人网上,被朋友们发现。 后来写在微博里,被朋友们发现。 后来写在知乎里,被朋友们发现。 后来淹没在网易云强大的评论区里。 我需要一个地方,一个可以光明正大写出来的地方。 不用担心被任何人看到,不需要任何解释。 网易云可以把所有的悲伤,变成段子。

出于大众对网易云音乐的喜爱,这次文本挖掘我放在了这里,希望能发现些有趣的东西。

二、所需工具 Anaconda 3.5.0 Pycharm Node.js Mongodb Studio 3T RStudio 三、数据爬取 3.1 环境搭建

本文基于Scrapy框架爬取数据。使用pip install 来安装scrapy需要安装大量的依赖库:

wheel pip install wheel lxml pip install D:\Downloads\Scrapy\lxml-4.3.0-cp36-cp36m-win_amd64.whl PyOpenssl pip install D:\Downloads\Scrapy\pyOpenSSL-18.0.0-py2.py3-none-any.whl Twisted pip install D:\Downloads\Scrapy\Twisted-18.9.0-cp36-cp36m-win_amd64.whl Pywin32 可执行文件,挑选与Python对应版本安装就好。 Scrapy pip install scrapy

这里我使用了Anaconda来安装scrapy,安装时只需要一条语句:

conda install scrapy 3.2 网站分析

网易云音乐首页:

image.png

爬取思路有两种:

1.基于网页原代码,利用正则表达式、XPath等获取数据;

2.基于每次请求的API,直接获取所需数据;

本文采用第二种,针对电视剧《旋风少女》插曲的评论做简单说明:

image.png 查看NetWork,发起请求,我们可以看到,数据保存在这里: image.png

请求地址为:https://music.163.com/weapi/v1/resource/comments/R_SO_4_28936510?csrf_token=

image.png

但是Request HEaders里的Cookie值、FromData里的params、encSecKey都是加密过的。开始解密:

image.png

然后,我从一众解密大佬的海谈阔论中发现了这个神奇的存在,哈哈,众多泥石流里的一股清泉啊。没错,就是这个链接:

http://music.163.com/api/v1/resource/comments/R_SO_4_28936510

image.png

很好,狂喜。但是很不巧的是网易云设置了反爬虫,根本下不不了手,爬虫时会出现以下错误:

{"code":-460,"msg":"Cheating"}

这是网上存在的解决办法:

更换动态IP的:

我跟网易云音乐爬虫不得不说的故事(文末附精彩评论)

复制请求头的:

Python爬网易云音乐的那些事

说明:上面两种方法在现在是行不通的,网易云加强了反爬虫机制,对请求头中的Cookie值进行了加密,所以有了下面这些对请求头中的Cookie值进行解密的:

如何爬网易云音乐的评论数? 用Python代码来下载任意指定网易云歌曲(超详细版)

但是,这种解密方法繁琐复杂,本文采用@Binaryify团队开发的[NeteaseCloudMusicApi]获取请求,这是一个相当便利、好用的API,感谢Binaryify。

3.3 功能特性

此次爬虫,下面的所有功能,都可以实现,是的,都可以!只要你想要的,在网易云上面有的,都可以爬,随便爬!!!就是这么任性和嚣张!奈我何?!哈哈哈!

获取用户信息 , 歌单,收藏,mv, dj 数量 获取用户歌单 获取用户电台 获取用户关注列表 获取用户粉丝列表 获取用户动态 获取用户播放记录 获取精品歌单 获取歌单详情 搜索 搜索建议 获取歌词 歌曲评论 收藏单曲到歌单 专辑评论 歌单评论 mv 评论 电台节目评论 banner 获取歌曲详情 获取专辑内容 获取歌手单曲 获取歌手 mv 获取歌手专辑 获取歌手描述 获取相似歌手 获取相似歌单 相似 mv 获取相似音乐 获取最近 5 个听了这首歌的用户 获取每日推荐歌单 获取每日推荐歌曲 私人 FM 签到 喜欢音乐 垃圾桶 歌单 ( 网友精选碟 ) 新碟上架 热门歌手 最新 mv 推荐 mv 推荐歌单 推荐新音乐 推荐电台 推荐节目 独家放送 mv 排行 获取 mv 数据 播放 mv/视频 排行榜 歌手榜 云盘 电台 - 推荐 电台 - 分类 电台 - 分类推荐 电台 - 订阅 电台 - 详情 电台 - 节目 给评论点赞 获取动态 获取热搜 发送私信 发送私信歌单 新建歌单 收藏/取消收藏歌单 歌单分类 收藏的歌手列表 订阅的电台列表 相关歌单推荐 付费精选接口 音乐是否可用检查接口 登录状态 获取视频数据 发送/删除评论 热门评论 视频评论 退出登录 所有榜单 所有榜单内容摘要 收藏视频 收藏 MV 视频详情 相关视频 关注用户 新歌速递 喜欢音乐列表(无序) 收藏的 MV 列表

本文以其中几个为例,进行数据爬取和文本挖掘:

3.3 歌单

我们找到歌单页面为下:

image.png

可以看到: 语种有:华语、欧美、日语、韩语、小语种; 风格有:流行、摇滚、民谣、电子、舞曲、说唱、轻音乐、说唱、爵士、乡村、古典、民族、英伦、金属、朋克、蓝调、雷鬼、世界音乐、拉丁、古风等;还有对歌单的场景、情感、主题分类。

我们不对其进行帅选,爬取所有种类的歌单。当每页为35个歌单的时候,一共有38页;当每页为20个歌单的时候,一共有66页,我们把66页一共1306个的歌单信息爬取下来:

class MenuSpider(scrapy.Spider): name = 'menu' allowed_domains = ['localhost:3000'] start_urls = ['http://localhost:3000/'] allplaylist_url = 'http://localhost:3000/top/playlist?order=hot&cat=%E5%85%A8%E9%83%A8&limit=20&offset={offset}' def start_requests(self): for i in range(0, 66): yield Request(self.allplaylist_url.format(offset=i * 20), callback=self.parse_allplaylist) def parse_allplaylist(self, response): result = json.loads(response.text) item = MusicmenuItem() for field in item.fields: if field in result.keys(): item[field] = result.get(field) yield item 3.3 歌曲 image.png

我们选择爬取歌曲评论信息的时候一并把歌曲信息爬下来。

3.5 歌曲评论

我们的目的是获取K个歌单下面的M首歌曲的前N页评论信息。

image.png

2018年12月30日下午3点27分:

元旦公休,周日,CS下雪,CSU美不胜收。 从前晚、昨天、昨晚01:00点,我一直在一个问题上挣扎,那就是爬取前4首歌的前3页评论时,为什么爬取的时候只会爬到7条记录:第一首第一页,第二首第一页,第三首第一页,第四首一、二、三页,现在这个问题终于解决。 其中,有包括:Scrapy的调试:pycharm下打开、执行并调试scrapy爬虫程序。

Crawer 1.0 # -*- coding: utf-8 -*- sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8') #改变标准输出的默认编码 class MusiccommentsSpider(scrapy.Spider): name = 'musiccomments' allowed_domains = ['localhost:3000'] start_urls = ['http://localhost:3000/comment/music?id=296883/'] comment_url = 'http://localhost:3000/comment/music?id={id}&offset={offset}&limit=20' playlist_url = 'http://localhost:3000/playlist/detail?id=2571516884' num_comment = 0 song_id=0 def start_requests(self): yield Request(self.playlist_url, callback=self.parse_playlist) #yield Request(self.comment_url.format(offset=self.num_comment), callback=self.parse_comment,dont_filter=True) def parse_playlist(self, response): result = json.loads(response.text) item = WangyiyunPlaylistItem() #print(result.get('playlist').get('tracks').get('name')) for field in item.fields: if field in result.keys(): item[field] = result.get(field) yield item #global song_id for i in range(0, 4): #for i in range(0,(result.get('playlist').get('trackCount'))-1): self.num_comment=0 self.song_id = result.get('playlist').get('tracks')[i].get('id') yield Request(self.comment_url.format(id=self.song_id,offset=self.num_comment), callback=self.parse_comment,dont_filter=True) def parse_comment(self, response): result = json.loads(response.text) item = WangyiyunCommentItem() #print(response.text.encode('utf-8','ignore')) for field in item.fields: if field in result.keys(): item[field] = result.get(field) yield item self.num_comment = self.num_comment + 1 if self.num_comment 5

得到了69条记录:

image.png

其中挑选了一个id为1389014,昵称叫猜猜寻的进行分析

4.2.2 关注者的地区分布

导入之前爬取到的用户数据

import pymongo import pandas as pd import numpy as np client = pymongo.MongoClient(host='localhost', port=27017) db = client['music'] collection = db['users3'] # 将数据库数据转为dataFrame user = pd.DataFrame(list(collection.find()))

查看数据维度:

print(user.shape)

有14974个用户,每个用户下面有13个字段信息:

(14974, 13)

查看字段名称:

['_id', 'adValid', 'bindings', 'code', 'createDays', 'createTime', 'level', 'listenSongs', 'mobileSign', 'pcSign', 'peopleCanSeeMyPlayRecord', 'profile', 'userPoint']

我们选取其中的profile进行分析:

profile=pd.DataFrame(user['profile'])

profile下面有41个字段,我们将14974个用户的profile字段下面的其中两个字段:province和userId提取出来,合并成一个数据框。

result=pd.DataFrame([[9003,110000]]) for i in range(1,14974): province=profile.iloc[i][0].get('province') userId=profile.iloc[i][0].get('userId') #列合并 userInfo=pd.DataFrame([[userId,province]]) #行合并 result=pd.concat([result,userInfo],ignore_index=True) #列命名 result.columns = ['userId','province']

统计每个省份所包含的网易云音乐用户数量。

data = result.groupby(result['province']).count() data.to_csv("userProvinceInfo.csv", sep=',', header=True, index=False)

由于原始数据中province的值为行政区划代码,需要根据行政区划代码表还原用户的所在省份信息。

install.packages("xlsx") library(xlsx) userInfo=read.csv("userProvinceInfo.csv") code=read.table("clipboard",header = TRUE) pro=matrix(0,nrow(userInfo),1) for(i in 3:36){ pro[i-2,1]=as.matrix(code[which(userInfo[i,2]==code[,1]),2])[1,1] } pro=pro[-c(35,36,37),] data=cbind(userInfo[-c(35,36,37),1],pro) colnames(data)


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有