网易云音乐评论刷赞音乐怎么刷评论,粉丝,转发,收藏?

网易云音乐的评论区到底怎么了? - 知乎45被浏览<strong class="NumberBoard-itemValue" title="2分享邀请回答6添加评论分享收藏感谢收起8添加评论分享收藏感谢收起&&&&&& 之前已经用python获取了网易云音乐的评论数据,下一步的工作就是数据分析了。一般数据分析无非是采用(统计)数字、图或者表的形式来展现数据之中隐含的信息。其中图和表显然是最直观的了。所以这里我使用可视化的方法即用图形来展示从评论中挖掘到的各种信息。
&&&&&&& 可视化的工具有很多,比如常见的有excel还有一些专门的绘图软件,各个编程语言当然也有很多可视化的包或者库,比如统计上使用很多的R语言就有很多可视化的库,我最喜欢的就是ggplot2了,我使用R语言主要用于数据的清洗以及可视化,其丰富的包(package)大大简化了数据分析的工作量,而且可以绘制非常复杂、精美的图表,以后有机会可以给大家专门介绍一下。python中可视化的库也很多,最著名的的莫过于matplotlib了,这是一个面向对象的绘图库,很多方面的用法和matlab类似(从matlab的绘图风格借鉴而来),由于我以前使用过一段时间的matlab,所以上手还是比较快,其他的还有seaborn(据说是对matplotlib的改进和封装,使用起来更加方便,没用过,有时间再研究下)、pygraph等。但是使用最广泛的还是matplotlib。javascript有Echarts(百度的)等,这个我还没接触过,是一个可以网页上进行可视化的函数库,据说很棒。其他的当然还有特别多,这里我就不一一列举了。有兴趣的小伙伴可以自行去查阅资料。这里我决定使用matplotlib,主要是因为最近主要接触的就是python,但是数据可视化方面的库用的不多,刚好可以拿这次的数据来练练手,其次我接触过matlab,相信对matplotlib入手会更快一点。
&&&&&&&& 这次主要分析的有以下几个方面:1、一首歌曲评论数目随时间变化的趋势,比如每天的评论数变化,每月的评论数变化等等。2、一首歌曲点赞数目分布的情况,比如0-10赞有多少个,占多少比例,1000赞以上占多大比例等等。3、热门评论词云的制作,主要想通过词云,将文本挖掘的结果可视化,可以看出哪些是高频词汇等。4、一首歌曲评论者的基本信息的情况展示,比如评论者的地区分布,年龄分布、累计听歌数目分布、动态分布、粉丝数分布等等。通过这些信息,可以直观看出一首歌曲被哪些地区、哪些年龄段的人所喜爱,以及听歌的人具有什么的特点等等。
  && 好了,废话不多说了,直接上图吧。
&&&&&&&& 首先来看一些歌曲评论数随时间的变化。
   & & & 上面的5张图我分别选取了5首不同的歌曲,有华语歌曲也有英文歌曲,有的起止时间很长(从13年就开始),也有的起止时间很短(从最近几个月才开始)。总的来说可以分为两种模式,一种是开始一段时间评论数很少,后来逐渐呈现爆发式地增长,前面三首歌《同桌的你》、《七里香》、《All Too Well》都是这种模式,而后面两首歌《不要再孤单》、《stay》则是恰好相反,歌曲刚刚出来的那几天评论数猛增,后面评论数逐渐下降,之后趋于平稳。通过分析,其实也很好理解,第一种模式的歌曲,往往都是早期曲库中就存在的歌曲(也可以称之为“老歌”),那个时候网易云音乐才刚刚出来,用户数目还很少,所以这些歌曲每天的评论数很少(没记错的话网易云应该是12、13年左右才出来的吧),后来网易云一路走红,直至现在号称有2亿用户,由于用户基数大,所以这些经典的老歌自然评论数猛增了,可以想见,这种评论爆发式增长和网易云音乐用户的增长趋势应该是基本一致的。而至于第二种模式,出现这种模式的歌曲往往都是比较新的歌曲,而且往往伴随着影视剧的火热突然火起来,比如《不要再孤单》就是电影的主题曲,电影刚上映的那段时间,歌随影热,评论数自然爆发式增长,后来这段热潮过去了,评论数自然就降下来了(当然这种歌曲应该以网络歌曲居多,只是某一段时间特别火,不黑,我觉得真正的经典评论数应该不会大起大落,比如《晴天》、《see you again》等)。当然我只是分析了两种典型的评论随时间变化的模式,实际肯定不止这两种模式,大家可以自行去探索。
&&&&&&&&&&&
&&&&&&&&&&&&&&& 前面5张图都是使用折线图来展示的,图6使用的是柱状图。我们来看下图7,图7展示的最近一段时间比较火的李玉刚的歌曲《刚好遇见你》的评论数随时间的分布,让人感到奇怪的是,中间从大约1月23日到3月24日的每天的评论量竟然是0!这怎么可能呢?难道真的是这样么?当然不是。我解释一下原因,这是程序本身的bug,我在抓取评论数过10W的歌曲的过程中发现,我最终看似抓取了全部的评论,但是实际上在去除重复之后,我只得到了部分的数据,每次大概只能得到2W到3W左右的数据,其他的数据就缺失了。至今我也没能解决这个问题,个人觉得是服务器做了什么限制,如果有朋友知道该怎么解决这个问题,望能不吝赐教!
      除了可以从宏观上看一首歌曲每天或者每月的评论数分布之外,我们还可以将不同的歌曲评论随时间变化放到一起对比,或者将一首歌曲每月的评论数放在一起进行对比。
&&&&&&&&&&&&&&&&&& 图 8 就展示了四首不同的歌曲在某一个时间段评论数目随时间变化,图9展示了《同桌的你》从16年8月到17年3月这8个月的时间里每月评论数的分布情况,图10则是《越长大越孤单》从16年4月到17年3月这12个月的每月评论数分布。其实,这种图形很容易做出,因为我已经将绘图函数做了封装,可以设置自定义参数字典,来生成自己想要的不同的图形,也可以选择绘制图形的种类、颜色以及绘制的时间段、时间间隔等,在文末我会说明这一点。
       接下来,看一下评论点赞数目的分布情况。
    图10和图11展示的点赞数目分布我去除了10赞以下的,原因是我发现一首歌曲绝大部分的点赞数目(超过99%)都是10赞以下的,这也与我们的常识相一致,所以为了方便我就直接去除了。通过上面的两张图我们可以看出,红色区域面积最大,即100赞到1000占据了全部10赞以上评论的绝大部分,其次是10到100赞,然后是1000赞到10000赞,最少的是1W赞以上,我发现大部分歌曲基本都是呈现这个规律,所以只在这里简单提一下,就不做详细分析了。
&&&&&&&&&& 接下来分析歌曲热门评论的词云展示,其实python的词云,我之前的一篇随笔也有提到过,使用wordcloud(绘制词云)和jieba(中文分词)即可。这里就不细说了。直接看图吧。
图 13 《不要再孤单》词云
图 14 & 周杰伦热门50首歌曲热门评论词云
图 15 Taylor Swift 热门歌曲热门评论词云
    从以上的词云中还是可以看出一首歌曲或者一位歌手,评论区中出现频率最高的是哪些词的。比如杰伦 的热门评论中反复出现的词就有周杰伦、青春、喜欢、女朋友、故事等等,一股青春怀旧风扑面而来啊。哈哈,其他有意思的大家自己去分析吧。
    最后,我想重点来分析一下,一首歌曲的评论者个人信息具有什么样的特点。我将这些特点放在一张图中,通过多张饼图来展示了,见下。
     图 16 到 图 22 展示了不同的歌手(有中有外,有老有少)以及不同的歌曲(老歌和新歌)评论者多方面的信息分布。通过对比不难发现如下的规律。周杰伦粉丝主要还是以90后和95后为主,这二者之和超过80%。周杰伦、Taylor Swift、Bruno Mars 这三位歌手评论者累计听歌在之间的人数(算是累计听歌较多)占比要显著高于其他几个歌手,粉丝人数在10-100以及100-1000的比例也是如此,这几位都可以称得上时下的歌坛巨星,评论者的听歌数目以及粉丝人数可以在一定程度上反映出对音乐的喜爱程度以及对音乐的鉴赏力吧(不黑)。TFboys评论者中00后的比例高达25%,为列举的所有歌手中最高,其他歌手00后的比例均不超过10%,不过考虑到tf是美少男组合,这也就可以说的通了。刘德华歌曲的评论者中80后以及80前的比例之和近20%,而其他歌手这一数字基本在7%左右,这在一定程度上可以说明刘天王的粉丝最多的还是而立之后的中年人啊。再来看地区,一眼望去,无论是歌手还是歌曲,地区分布的前五中都出现了一个共同的身影,那就是北京市东城区,看来网易云上有相当一部分用户都是来自北京市东城区啊,不过考虑到北京市是我国的文化中心,许多明星、歌手均在北京定居,还有网易云上推荐的一些音乐人很多都在北京(东城区),这点就不难理解了。多次出现的地区还有广州市、成都市等等,这些都是经济较发达的地区,也是文化产业特别是音乐产业发达的地区(广州主要是粤语歌,而且离香港也很近,成都民谣应该很丰富(猜测))。这么一考虑,这些结果就不难理解了。当然,可以挖掘的其他信息还有很多,比如还有动态的分布等等,还可以按照音乐的类别进行对比等等,如果有兴趣,大家可以自己去完成这个工作。
      到这里,其实评论数据的可视化就差不多结束了。其实我做得很粗糙,很多分析也纯属我个人的臆测,大家随便看看就好。最后我还有几点要补充的。
&&&&&&&&&&&&&&&& 在这次写代码的过程中,我一开始觉得应该写不了几行应该就把数据可视化搞定了,没想到最终还花了我挺长的时间,加到一起代码有七八百行,当然,很多东西都是可以精简的,我懒得去弄了。我将绘图的几个函数抽象了出来,可以通过简单地配置参数字典(settings)传入函数来配置自己想要的图形,比如可以控制要绘制散点图还是柱状图,控制颜色、时间间隔等等,只需要更改相应的参数字典就可以了。主要有两个类,一个是NetCloudCrawl类,主要用于歌曲评论数的抓取,还有一个是NetCloudProcessor,主要用于生成相关文件以及绘制可视化图形。几个主要的函数如下:1 create_all_necessary_files(song_id,song_name) 这个函数可以自动完成评论数据的抓取(包括热门评论)、保存到文件,生成必要的统计txt文件,生成词云等。只需要传入歌曲id(song_id)以及歌曲名字(song_name)即可。2 plot_comments(song_name,settings)函数,用于绘制基本的评论或者点赞图形,settings为参数字典,用于控制绘图方式以及呈现结果。3 sub_plot_comments(song_names_list,settings,row,col)用于在一张图中绘制多个歌曲的评论分布,song_names_list 为歌曲名字列表,settings 为绘图参数字典,row为子图行数,col为子图列数。& 4 draw_wordcloud 用于绘制词云& 5 sub_plot_months 用于在一张图中绘制某一首歌曲在某几个月(按月绘制)中的评论分布。6 sub_plot_commenters_info 用于绘制歌曲评论者的各项信息分布 。 还有三个 测试函数,分别是 sub_plot_months_test、subplot_test、plot_comments_test 直接调用相应的绘图函数,可以方便地在其中配置参数字典,然后直接调用测试函数即可绘制图形。所以绘制图形其实只有简单的两步:第一步,确定歌曲名称以及id(直接去网易云音乐上找相应歌曲链接即可,?id= 后面的数字就是歌曲id),然后调用create_all_necessary_files 生成所需要的文件;第二步:调用相应的绘图函数,一般只需要传入歌曲名字以及参数字典即可。
&&&&&&&&&& 最后还是附上全部的代码如下:
NetCloud_spider3.py
1 #!/usr/bin/env python2.7
2 # -*- coding: utf-8 -*-
4 # @Author : Lyrichu
5 # @Email
: NetCloud_spider3.py
8 @Description:
9 网易云音乐评论爬虫,可以完整爬取整个评论
10 部分参考了@平胸小仙女的文章(地址:https://www.zhihu.com/question/)
11 post加密部分也给出了,可以参考原帖:
12 作者:平胸小仙女
13 链接:https://www.zhihu.com/question//answer/
14 来源:知乎
16 from Crypto.Cipher import AES
17 import base64
18 import requests
19 import json
20 import codecs
21 import time
22 import os
24 # 定义抓取评论类NetCloudCrawl
25 class NetCloudCrawl(object):
def __init__(self):
# 头部信息
self.headers = {
'Host':"music.163.com",
'User-Agent':"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/ Firefox/52.0",
'Accept-Language':"zh-CN,q=0.8,en-US;q=0.5,q=0.3",
'Accept-Encoding':"gzip, deflate",
'Content-Type':"application/x-www-form-urlencoded",
'Cookie':"_ntes_nnid=b121e078dee797cdb30e0fd,7; _ntes_nuid=b121e078dee797cdb30e0 JSESSIONID-WYYY=yfqt9ofhY%5CIYNkXW71TqY5OtSZyjE%2FoswGgtl4dMv3Oa7%5CQ50T%2FVaee%2FMSsCifHE0TGtRMYhSPpr20i%5CRO%2BO%2B9pbbJnrUvGzkibhNqw3Tlgn%5Coil%2FrW7zFZZWSA3K9gD77MPSVH6fnv5hIT8ms70MNB3CxK5r3ecj3tFMlWFbFOZmGw%5C%3A0; _iuqxldmzr_=32; vjuids=c8cad006a.0.af8; vjlast=..21; __gads=ID=a9eed5e3cae4d252:T=:S=ALNI_Mb5XX2vlkjsiU5cIy91-ToUDoFxIw; vinfo_n_f_l_n3=411a2def7f75a62e.1.1.9.5.2; P_INFO=||1|study|00&99|null&null&null#hub&#0#0||study_client|@163. NTES_CMT_USER_INFO=Cm155****4439%7Chttps%3A%2F%2Fsimg.ws.126.net%2Fe%2Fimg5.cache.netease.com%2Ftie%2Fimages%2Fyun%2Fphoto_default_62.png.39x39.100.jpg%7Cfalse%7CbTE1NTI3NTk0NDM5QDE2My5jb20%3D; usertrack=c+5+hljHgU0T1FDmA66MAg==; Province=027; City=027; _ga=GA1.2..; __utma=; __utmc=; __utmz=.2.utmcsr=baidu|utmccn=(organic)|utmcmd= playerid=; __utmb=.10.",
'Connection':"keep-alive",
'Referer':'http://music.163.com/',
'Upgrade-Insecure-Requests':"<span style="color: #"
# 设置代理服务器
self.proxies= {
'http:':'http://180.123.225.51',
'https:':'https://111.72.126.116'
# offset的取值为:(评论页数-1)*20,total第一页为true,其余页为false
# first_param = '{rid:"", offset:"0", total:"true", limit:"20", csrf_token:""}' # 第一个参数
self.second_param = "<span style="color: #0001" # 第二个参数
# 第三个参数
self.third_param = "<span style="color: #e0b509fdbcdf2ff68ace615bb7bab17a876aea8a5aa76d2eee341f56135fccf12ecbda14af6c9d05c4f7f0cbeecce10b424d813cfe47b97ddefe289dc6935b3eceb8e7"
# 第四个参数
self.forth_param = "<span style="color: #CoJUm6Qyw8W8jud"
self.encSecKey = "<span style="color: #7348aecb5e556c066de214e531faadd1c55d814f9be95fd06d6bff9f4c7a41f831ffd2ea02ca919dd0a50ebfad512f5f1ca21aec60bcffca5eca9a0dba6d6f5ecfffc28f3fe7de08fcdbcf739e135637c"
# 获取参数
def get_params(self,page): # page为传入页数
first_key = self.forth_param
second_key = 16 * 'F'
iv = "<span style="color: #08"
if(page == 1): # 如果为第一页
first_param = '{rid:"", offset:"0", total:"true", limit:"20", csrf_token:""}'
h_encText = self.AES_encrypt(first_param, first_key,iv)
offset = str((page-1)*20)
first_param = '{rid:"", offset:"%s", total:"%s", limit:"20", csrf_token:""}' %(offset,'false')
h_encText = self.AES_encrypt(first_param, first_key, iv)
h_encText = self.AES_encrypt(h_encText, second_key, iv)
return h_encText
# 解密过程
def AES_encrypt(self,text, key, iv):
pad = 16 - len(text) % 16
text = text + pad * chr(pad)
encryptor = AES.new(key, AES.MODE_CBC, iv)
encrypt_text = encryptor.encrypt(text)
encrypt_text = base64.b64encode(encrypt_text)
return encrypt_text
# 获得评论json数据
def get_json(self,url, params, encSecKey):
"params": params,
"encSecKey": encSecKey
response = requests.post(url, headers=self.headers, data=data,proxies = self.proxies)
return response.content
# 抓取热门评论,返回热评列表
def get_hot_comments(self,url):
hot_comments_list = []
hot_comments_list.append(u"用户ID 用户昵称 用户头像地址 评论时间 点赞总数 评论内容\n")
params = self.get_params(1) # 第一页
json_text = self.get_json(url,params,self.encSecKey)
json_dict = json.loads(json_text)
hot_comments = json_dict['hotComments'] # 热门评论
print("共有%d条热门评论!" % len(hot_comments))
for item in hot_comments:
comment = item['content'] # 评论内容
likedCount = item['likedCount'] # 点赞总数
comment_time = item['time'] # 评论时间(时间戳)
userID = item['user']['userId'] # 评论者id
<span style="color: #0
nickname = item['user']['nickname'] # 昵称
<span style="color: #1
avatarUrl = item['user']['avatarUrl'] # 头像地址
<span style="color: #2
comment_info = unicode(userID) + u" " + nickname + u" " + avatarUrl + u" " + unicode(comment_time) + u" " + unicode(likedCount) + u" " + comment + u"\n"
<span style="color: #3
hot_comments_list.append(comment_info)
<span style="color: #4
return hot_comments_list
<span style="color: #5
<span style="color: #6
# 抓取某一首歌的全部评论
<span style="color: #7
def get_all_comments(self,url):
<span style="color: #8
all_comments_list = [] # 存放所有评论
<span style="color: #9
all_comments_list.append(u"用户ID 用户昵称 用户头像地址 评论时间 点赞总数 评论内容\n") # 头部信息
<span style="color: #0
params = self.get_params(1)
<span style="color: #1
json_text = self.get_json(url,params,self.encSecKey)
<span style="color: #2
json_dict = json.loads(json_text)
<span style="color: #3
comments_num = int(json_dict['total'])
<span style="color: #4
if(comments_num % 20 == 0):
<span style="color: #5
page = comments_num / 20
<span style="color: #6
<span style="color: #7
page = int(comments_num / 20) + 1
<span style="color: #8
print("共有%d页评论!" % page)
<span style="color: #9
for i in range(page):
# 逐页抓取
<span style="color: #0
params = self.get_params(i+1)
<span style="color: #1
json_text = self.get_json(url,params,self.encSecKey)
<span style="color: #2
json_dict = json.loads(json_text)
<span style="color: #3
if i == 0:
<span style="color: #4
print("共有%d条评论!" % comments_num) # 全部评论总数
<span style="color: #5
for item in json_dict['comments']:
<span style="color: #6
comment = item['content'] # 评论内容
<span style="color: #7
likedCount = item['likedCount'] # 点赞总数
<span style="color: #8
comment_time = item['time'] # 评论时间(时间戳)
<span style="color: #9
userID = item['user']['userId'] # 评论者id
<span style="color: #0
nickname = item['user']['nickname'] # 昵称
<span style="color: #1
avatarUrl = item['user']['avatarUrl'] # 头像地址
<span style="color: #2
comment_info = unicode(userID) + u" " + nickname + u" " + avatarUrl + u" " + unicode(comment_time) + u" " + unicode(likedCount) + u" " + comment + u"\n"
<span style="color: #3
all_comments_list.append(comment_info)
<span style="color: #4
print("第%d页抓取完毕!" % (i+1))
<span style="color: #5
return all_comments_list
<span style="color: #6
<span style="color: #7
<span style="color: #8
# 将评论写入文本文件
<span style="color: #9
def save_to_file(self,list,filename):
<span style="color: #0
with codecs.open(filename,'a',encoding='utf-8') as f:
<span style="color: #1
f.writelines(list)
<span style="color: #2
print("写入文件成功!")
<span style="color: #3
<span style="color: #4
# 抓取歌曲评论
<span style="color: #5
def save_all_comments_to_file(self,song_id,song_name):
<span style="color: #6
start_time = time.time() # 开始时间
<span style="color: #7
url = "http://music.163.com/weapi/v1/resource/comments/R_SO_4_%d/?csrf_token=" % song_id
<span style="color: #8
if(os.path.exists(song_name)):
<span style="color: #9
filename = u"%s/%s.txt" % (song_name,song_name)
<span style="color: #0
<span style="color: #1
os.mkdir(song_name)
<span style="color: #2
filename = u"%s/%s.txt" % (song_name,song_name)
<span style="color: #3
all_comments_list = self.get_all_comments(url)
<span style="color: #4
self.save_to_file(all_comments_list,filename)
<span style="color: #5
end_time = time.time() #结束时间
<span style="color: #6
print(u"抓取歌曲《%s》耗时%f秒." % (song_name,end_time - start_time))
NetCloud_comments_plot.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
4 # @Author : Lyrichu
5 # @Email
: NetCloud_comments_plot.py
8 @Description:
9 对抓取来的网易云评论数据进行简单的可视化分析
11 from NetCloud_spider3 import NetCloudCrawl
12 import requests
13 import matplotlib.dates as mdates
14 from pylab import *
15 mpl.rcParams['font.sans-serif'] = ['SimHei']
# 防止无法显示中文
16 import matplotlib.pyplot as plt
17 from datetime import datetime
18 import re
19 import time
20 import pandas as pd
21 import codecs
22 import jieba
23 from wordcloud import WordCloud
24 from scipy.misc import imread
25 from os import path
26 import os
29 class NetCloudProcessor(NetCloudCrawl):
# 读取评论文本数据,返回一个列表,列表的每个元素为一个字典,字典中包含用户id,评论内容等
def read_comments_file(self,filename):
list_comments = [] # 评论数据列表
with open(filename,'r') as f:
comments_list = f.readlines() # 读取文本,按行读取,返回列表
del comments_list[0] # 删除首个元素
comments_list = list(set(comments_list)) # 去除重复数据
count_ = -1 # 记录评论数
for comment in comments_list:
comment = comment.replace("\n","") # 去除末尾的换行符
if (re.search(re.compile(r'^\d+?'),comment)): # 如果以数字开头
comment_split = comment.split(' ',5) # 以空格分割(默认)
comment_dict = {}
comment_dict['userID'] = comment_split[0] # 用户ID
comment_dict['nickname'] = comment_split[1] # 用户昵称
comment_dict['avatarUrl'] = comment_split[2] # 用户头像地址
comment_dict['comment_time'] = int(comment_split[3])# 评论时间
comment_dict['likedCount'] = int(comment_split[4])# 点赞总数
comment_dict['comment_content'] = comment_split[5] # 评论内容
list_comments.append(comment_dict)
count_ += 1
list_comments[count_]['comment_content'] += comment
# 将评论追加到上一个字典
except Exception,e:
list_comments.sort(key= lambda x:x['comment_time'])
print(u"去除重复之后有%d条评论!" % (count_+1))
return (count_+1,list_comments) # 返回评论总数以及处理完的评论内容
# 将网易云的时间戳转换为年-月-日的日期函数
# 时间戳需要先除以1000才能得到真实的时间戳
# format 为要转换的日期格式
def from_timestamp_to_date(self,time_stamp,format):
time_stamp = time_stamp*0.001
real_date = time.strftime(format,time.localtime(time_stamp))
return real_date
# 统计相关数据写入文本文件
def count_comments_info(self,comments_list,count_,song_name):
x_date_Ym = [] # 评论数按年月进行统计
x_date_Ymd = [] # 评论数按年月日进行统计
x_likedCount = [] # 点赞总数分布
for i in range(count_):
time_stamp = comments_list[i]['comment_time'] # 时间戳
real_date_Ym = self.from_timestamp_to_date(time_stamp,'%Y-%m') # 按年月进行统计
real_date_Ymd = self.from_timestamp_to_date(time_stamp,'%Y-%m-%d') # 按年月日统计
likedCount = comments_list[i]['likedCount'] # 点赞总数
x_date_Ym.append(real_date_Ym)
x_date_Ymd.append(real_date_Ymd)
x_likedCount.append(likedCount)
x_date_Ym_no_repeat = []
y_date_Ym_count = []
x_date_Ymd_no_repeat = []
y_date_Ymd_count = []
x_likedCount_no_repeat = []
y_likedCount_count = []
for date_ in x_date_Ym:
if date_ not in x_date_Ym_no_repeat:
x_date_Ym_no_repeat.append(date_)
y_date_Ym_count.append(x_date_Ym.count(date_))
for date_ in x_date_Ymd:
if date_ not in x_date_Ymd_no_repeat:
x_date_Ymd_no_repeat.append(date_)
y_date_Ymd_count.append(x_date_Ymd.count(date_))
for likedCount in x_likedCount:
<span style="color: #0
if likedCount not in x_likedCount_no_repeat:
<span style="color: #1
x_likedCount_no_repeat.append(likedCount)
<span style="color: #2
y_likedCount_count.append(x_likedCount.count(likedCount))
<span style="color: #3
# 将统计的数据存入txt文件
<span style="color: #4
with open(u"%s/comments_num_by_Ym.txt" % song_name,"w") as f:
<span style="color: #5
f.write("date_Ym comments_num\n")
<span style="color: #6
for index,date_Ym in enumerate(x_date_Ym_no_repeat):
<span style="color: #7
f.write(x_date_Ym_no_repeat[index] + " " + str(y_date_Ym_count[index]) + "\n")
<span style="color: #8
print(u"成功写入comments_num_by_Ym.txt!")
<span style="color: #9
with open(u"%s/comments_num_by_Ymd.txt" % song_name,"w") as f:
<span style="color: #0
f.write("date_Ymd comments_num\n")
<span style="color: #1
for index,date_Ymd in enumerate(x_date_Ymd_no_repeat):
<span style="color: #2
f.write(x_date_Ymd_no_repeat[index] + " " + str(y_date_Ymd_count[index]) + "\n")
<span style="color: #3
print(u"成功写入comments_num_by_Ymd.txt!")
<span style="color: #4
with open(u"%s/likedCount.txt" % song_name,"w") as f:
<span style="color: #5
f.write("likedCount count_num\n")
<span style="color: #6
for index,likedCount in enumerate(x_likedCount_no_repeat):
<span style="color: #7
f.write(str(x_likedCount_no_repeat[index]) + " " + str(y_likedCount_count[index]) + "\n")
<span style="color: #8
print(u"成功写入likedCount.txt!")
<span style="color: #9
# 得到处理过的x_date 和 count 统计信息
<span style="color: #0
def get_xdate_ycount(self,count_file_name,date_type,min_date_Ym,max_date_Ym,min_date_Ymd,max_date_Ymd):
<span style="color: #1
with open(count_file_name,'r') as f:
<span style="color: #2
list_count = f.readlines()
<span style="color: #3
# comment_or_like = list_count[0].replace("\n","").split(" ")[1] # 判断是评论数还是点赞数
<span style="color: #4
# song_name = count_file_name.split("/")[0] # 歌曲名字
<span style="color: #5
del list_count[0]
<span style="color: #6
x_date = []
<span style="color: #7
y_count = []
<span style="color: #8
for content in list_count:
<span style="color: #9
content.replace("\n","")
<span style="color: #0
res = content.split(' ')
<span style="color: #1
if(date_type == '%Y-%m-%d'):
<span style="color: #2
if(int("".join(res[0].split("-"))) &= int("".join(min_date_Ymd.split("-"))) and int("".join(res[0].split("-"))) &=
int("".join(max_date_Ymd.split("-")))):
<span style="color: #3
x_date.append(res[0])
<span style="color: #4
y_count.append(int(res[1]))
<span style="color: #5
<span style="color: #6
if(int("".join(res[0].split("-"))) &= int("".join(min_date_Ym.split("-"))) and int("".join(res[0].split("-"))) &=
int("".join(max_date_Ym.split("-")))):
<span style="color: #7
x_date.append(res[0])
<span style="color: #8
y_count.append(int(res[1]))
<span style="color: #9
return (x_date,y_count)
<span style="color: #0
<span style="color: #1
<span style="color: #2
# 绘制图形展示歌曲评论以及点赞分布
<span style="color: #3
# plot_type:为 'plot' 绘制散点图
为 'bar' 绘制条形图
<span style="color: #4
# date_type 为日期类型
<span style="color: #5
# time_distance 为时间间隔(必填)例如:5D 表示5天,1M 表示一个月
<span style="color: #6
# min_liked_num 为绘图时的最小点赞数
<span style="color: #7
# max_liked_num 为绘图时的最大点赞数
<span style="color: #8
# min_date_Ym 为最小日期(年-月形式)
<span style="color: #9
# max_date_Ym 为最大日期(年-月形式)
<span style="color: #0
# min_date_Ymd 为最小日期(年-月-日形式)
<span style="color: #1
# max_date_Ymd 为最大日期(年-月-日形式)
<span style="color: #2
def plot_comments(self,song_name,settings):
<span style="color: #3
comment_type = settings['comment_type']
<span style="color: #4
date_type = settings['date_type']
<span style="color: #5
plot_type = settings['plot_type']
<span style="color: #6
bar_width = settings['bar_width']
<span style="color: #7
rotation = settings['rotation']
<span style="color: #8
time_distance = settings['time_distance']
<span style="color: #9
min_date_Ymd = settings['min_date_Ymd']
<span style="color: #0
max_date_Ymd = settings['max_date_Ymd']
<span style="color: #1
min_date_Ym = settings['min_date_Ym']
<span style="color: #2
max_date_Ym = settings['max_date_Ym']
<span style="color: #3
if(comment_type):
<span style="color: #4
if(date_type == '%Y-%m-%d'):
<span style="color: #5
count_file_name = u"%s/comments_num_by_Ymd.txt" % song_name
<span style="color: #6
<span style="color: #7
count_file_name = u"%s/comments_num_by_Ym.txt" % song_name
<span style="color: #8
<span style="color: #9
count_file_name = u"%s/likedCount.txt" % song_name
<span style="color: #0
with open(count_file_name,'r') as f:
<span style="color: #1
list_count = f.readlines()
<span style="color: #2
del list_count[0]
<span style="color: #3
if(comment_type): # 如果是评论
<span style="color: #4
x_date = []
<span style="color: #5
y_count = []
<span style="color: #6
for content in list_count:
<span style="color: #7
content.replace("\n","")
<span style="color: #8
res = content.split(' ')
<span style="color: #9
if(date_type == '%Y-%m-%d'):
<span style="color: #0
if(int("".join(res[0].split("-"))) &= int("".join(min_date_Ymd.split("-"))) and int("".join(res[0].split("-"))) &=
int("".join(max_date_Ymd.split("-")))):
<span style="color: #1
x_date.append(res[0])
<span style="color: #2
y_count.append(int(res[1]))
<span style="color: #3
<span style="color: #4
if(int("".join(res[0].split("-"))) &= int("".join(min_date_Ym.split("-"))) and int("".join(res[0].split("-"))) &=
int("".join(max_date_Ym.split("-")))):
<span style="color: #5
x_date.append(res[0])
<span style="color: #6
y_count.append(int(res[1]))
<span style="color: #7
else: # 如果是点赞
<span style="color: #8
# 分为10-100,100-000,10000以上这5个区间,由于绝大多数歌曲评论点赞数都在10赞一下
<span style="color: #9
# 超过99%,所以10赞以下暂时忽略
<span style="color: #0
x_labels = [u'<span style="color: #-100',u'<span style="color: #0-1000',u'<span style="color: #00-10000',u'<span style="color: #000以上']
<span style="color: #1
y_count = [0,0,0,0]
<span style="color: #2
for content in list_count:
<span style="color: #3
content.replace("\n","")
<span style="color: #4
res = content.split(' ')
<span style="color: #5
if(int(res[0]) &= 100 and int(res[0]) &= 10):
<span style="color: #6
y_count[0] += int(res[1])
<span style="color: #7
elif(int(res[0]) &= 1000):
<span style="color: #8
y_count[1] += int(res[1])
<span style="color: #9
elif(int(res[0]) &= 10000):
<span style="color: #0
y_count[2] += int(res[1])
<span style="color: #1
<span style="color: #2
y_count[3] += int(res[1])
<span style="color: #3
# 如果是评论
<span style="color: #4
if(comment_type):
<span style="color: #5
type_text = u"评论"
<span style="color: #6
x = [datetime.strptime(d, date_type).date() for d in x_date]
<span style="color: #7
# 配置横坐标为日期类型
<span style="color: #8
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%s' % date_type))
<span style="color: #9
if(date_type == '%Y-%m-%d'):
<span style="color: #0
plt.gca().xaxis.set_major_locator(mdates.DayLocator())
<span style="color: #1
<span style="color: #2
plt.gca().xaxis.set_major_locator(mdates.MonthLocator())
<span style="color: #3
if(plot_type == 'plot'):
<span style="color: #4
plt.plot(x,y_count,color = settings['color'])
<span style="color: #5
elif(plot_type == 'bar'):
<span style="color: #6
plt.bar(x,y_count,width=bar_width,color = settings['color'])
<span style="color: #7
<span style="color: #8
plt.scatter(x,y_count,color = settings['color'])
<span style="color: #9
plt.gcf().autofmt_xdate(rotation=rotation)
# 自动旋转日期标记
<span style="color: #0
plt.title(u"网易云音乐歌曲《" + song_name + u"》" + type_text + u"数目分布")
<span style="color: #1
plt.xlabel(u"日期")
<span style="color: #2
plt.ylabel(u"数目")
<span style="color: #3
plt.xticks(pd.date_range(x[0],x[-1],freq="%s" % time_distance)) # 设置日期间隔
<span style="color: #4
plt.show()
<span style="color: #5
# 如果是点赞
<span style="color: #6
x = y_count
<span style="color: #7
type_text = u"点赞"
<span style="color: #8
pie_colors = settings['pie_colors']
<span style="color: #9
auto_pct = settings['auto_pct'] # 百分比保留几位小数
<span style="color: #0
expl = settings['expl'] # 每块距离圆心的距离
<span style="color: #1
plt.pie(x,labels = x_labels,explode=expl,colors = pie_colors,autopct = auto_pct)
<span style="color: #2
plt.title(u"网易云音乐歌曲《" + song_name + u"》" + type_text + u"数目分布")
<span style="color: #3
plt.legend(x_labels)
<span style="color: #4
plt.show()
<span style="color: #5
plt.close()
<span style="color: #6
<span style="color: #7
<span style="color: #8
# 生成某个歌曲的统计信息文件
<span style="color: #9
def generate_count_info_files(self,song_name):
<span style="color: #0
filename = "%s/%s.txt" %(song_name,song_name)
<span style="color: #1
count_,list_comments = self.read_comments_file(filename)
<span style="color: #2
print(u"%s有%d条评论!" % (song_name,count_))
<span style="color: #3
self.count_comments_info(list_comments,count_,song_name)
<span style="color: #4
<span style="color: #5
# 一步完成数据抓取,生成统计信息文件的工作
<span style="color: #6
def create_all_necessary_files(self,song_id,song_name):
<span style="color: #7
start_time = time.time()
<span style="color: #8
# 数据抓取并写入文件
<span style="color: #9
self.save_all_comments_to_file(song_id,song_name)
<span style="color: #0
# 生成热门评论文件
<span style="color: #1
url = "http://music.163.com/weapi/v1/resource/comments/R_SO_4_%d/?csrf_token=" % song_id
<span style="color: #2
hot_comments_list = self.get_hot_comments(url)
<span style="color: #3
self.save_to_file(hot_comments_list,u"%s/hotcomments.txt" % song_name)
<span style="color: #4
# 生成统计信息文件(3个)
<span style="color: #5
self.generate_count_info_files(song_name)
<span style="color: #6
# 生成所有评论者信息文件
<span style="color: #7
self.save_commenters_info_to_file(song_name)
<span style="color: #8
# 生成 评论词云(全部评论)
<span style="color: #9
self.draw_wordcloud(song_name,singer_name=False)
<span style="color: #0
end_time = time.time()
<span style="color: #1
print(u"任务完成!程序耗时%f秒!" %(end_time - start_time))
<span style="color: #2
# 得到某首歌曲下所有评论者(需要去除重复)的主页信息
<span style="color: #3
def get_commenters_info(self,filename):
<span style="color: #4
commenters_info_list = []
# 存放评论用户信息
<span style="color: #5
with codecs.open(filename,"r",encoding= 'utf-8') as f:
<span style="color: #6
lists = f.readlines()
<span style="color: #7
del lists[0]
# 删除第一行
<span style="color: #8
commenters_urls_list = [] # 评论者列表
<span style="color: #9
for info in lists:
<span style="color: #0
if(re.match(r'^\d.*?',info)):
<span style="color: #1
commenters_urls_list.append(u"http://music.163.com/user/home?id=" + info.split(" ")[0]) # 评论者主页地址
<span style="color: #2
commenters_urls_list = list(set(commenters_urls_list)) # 去除重复的人
<span style="color: #3
print("共有%d个不同评论者!" % len(commenters_urls_list))
<span style="color: #4
for index,url in enumerate(commenters_urls_list):
<span style="color: #5
<span style="color: #6
info_dict = {}
# 评论用户个人信息字典
<span style="color: #7
user_id_compile = re.compile(r'.*id=(\d+)')
<span style="color: #8
user_id = re.search(user_id_compile,url).group(1)
<span style="color: #9
html = requests.get(url,headers = self.headers).text
<span style="color: #0
event_count_compile = re.compile(r'&strong id="event_count"&(\d+?)&/strong&')
<span style="color: #1
event_count = re.search(event_count_compile,html).group(1) # 个人动态数目
<span style="color: #2
follow_count_compile = re.compile(r'&strong id="follow_count"&(\d+?)&/strong&')
<span style="color: #3
follow_count = re.search(follow_count_compile,html).group(1) # 关注人数
<span style="color: #4
fan_count_compile = re.compile(r'&strong id="fan_count"&(\d+?)&/strong&')
<span style="color: #5
fan_count = re.search(fan_count_compile,html).group(1)
<span style="color: #6
location_compile = re.compile(u'&span&所在地区:(.+?)&/span&') # 注意需要使用unicode编码,正则表达式才能匹配
<span style="color: #7
location_res = re.search(location_compile,html)
<span style="color: #8
if(location_res):
<span style="color: #9
location = location_res.group(1)
<span style="color: #0
<span style="color: #1
location = u"未知地区"
<span style="color: #2
self_description_compile = re.compile(u'&div class="inf s-fc3 f-brk"&个人介绍:(.*?)&/div&')
<span style="color: #3
if(re.search(self_description_compile,html)):
# 如果可以匹配到
<span style="color: #4
self_description = re.search(self_description_compile,html).group(1)
<span style="color: #5
<span style="color: #6
self_description = u"未知个人介绍"
<span style="color: #7
age_compile = re.compile(r'&span.*?data-age="(\d+)"&')
<span style="color: #8
if(re.search(age_compile,html)):
<span style="color: #9
age_time = re.search(age_compile,html).group(1) # 这个得到的是出生日期距离unix时间戳起点的距离
<span style="color: #0
# 需要将其转换为年龄
<span style="color: #1
age = () - (int(age_time)/(*3600)) # 真实的年龄
<span style="color: #2
<span style="color: #3
age = u"未知年龄"
<span style="color: #4
listening_songs_num_compile = re.compile(u'&h4&累积听歌(\d+?)首&/h4&')
<span style="color: #5
if(re.search(listening_songs_num_compile,html)):
<span style="color: #6
listening_songs_num = re.search(listening_songs_num_compile,html).group(1) # 听歌总数
<span style="color: #7
<span style="color: #8
listening_songs_num = u'未知听歌总数'
<span style="color: #9
info_dict['user_id'] = user_id
<span style="color: #0
info_dict['event_count'] = event_count # 动态总数
<span style="color: #1
info_dict['follow_count'] = follow_count # 关注总数
<span style="color: #2
info_dict['fan_count'] = fan_count
# 粉丝总数
<span style="color: #3
info_dict['location'] = location
# 所在地区
<span style="color: #4
info_dict['self_description'] = self_description # 个人介绍
<span style="color: #5
info_dict['age'] = age # 年龄
<span style="color: #6
info_dict['listening_songs_num'] = listening_songs_num # 累计听歌总数
<span style="color: #7
commenters_info_list.append(info_dict)
<span style="color: #8
print("成功添加%d个用户信息!" % (index+1))
<span style="color: #9
except Exception,e:
<span style="color: #0
<span style="color: #1
return commenters_info_list
# 返回评论者用户信息列表
<span style="color: #2
<span style="color: #3
# 保存评论者的信息
<span style="color: #4
def save_commenters_info_to_file(self,song_or_singer_name):
<span style="color: #5
if(os.path.exists(u"%s/%s.txt" % (song_or_singer_name,song_or_singer_name))):
<span style="color: #6
filename = u"%s/%s.txt" % (song_or_singer_name,song_or_singer_name)
<span style="color: #7
<span style="color: #8
filename = u"%s/hotcomments.txt" % song_or_singer_name
<span style="color: #9
commenters_info_lists = self.get_commenters_info(filename) # 得到用户信息列表
<span style="color: #0
with codecs.open(u"%s/commenters_info.txt" % song_or_singer_name,"w",encoding='utf-8') as f:
<span style="color: #1
f.write(u"用户ID 动态总数 关注总数 粉丝总数 所在地区 个人介绍 年龄 累计听歌总数\n")
<span style="color: #2
for info in commenters_info_lists:
<span style="color: #3
user_id = info['user_id'] # 用户id
<span style="color: #4
event_count = info['event_count'] # 动态数目
<span style="color: #5
follow_count = info['follow_count'] # 关注的人数
<span style="color: #6
fan_count = info['fan_count'] # 粉丝数
<span style="color: #7
location = info['location'] # 所在地区
<span style="color: #8
self_description = info['self_description'] # 个人介绍
<span style="color: #9
age = unicode(info['age']) # 年龄
<span style="color: #0
listening_songs_num = info['listening_songs_num'] # 累计听歌总数
<span style="color: #1
full_info = unicode(user_id) + u" " + event_count + u" " + follow_count + u" " + fan_count + u" " + location + u" " + self_description + u" " + age + u" " + listening_songs_num + u"\n"
<span style="color: #2
f.write(full_info)
<span style="color: #3
print(u"成功写入文件%s/commenters_info.txt" % song_or_singer_name)
<span style="color: #4
<span style="color: #5
# 得到某个歌手全部热门歌曲id列表
<span style="color: #6
def get_songs_ids(self,singer_url):
<span style="color: #7
ids_list = []
<span style="color: #8
html = requests.get(singer_url,headers = self.headers,proxies = self.proxies).text
<span style="color: #9
re_pattern = re.compile(r'&a href="/song\?id=(\d+?)"&.*?&/a&')
<span style="color: #0
ids = re.findall(re_pattern,html)
<span style="color: #1
for id in ids:
<span style="color: #2
ids_list.append(id)
<span style="color: #3
return ids_list
<span style="color: #4
# 得到某个歌手所有歌曲的热门评论
<span style="color: #5
def get_singer_all_hot_comments(self,singer_name,singer_id):
<span style="color: #6
singer_url = 'http://music.163.com/artist?id=%d' % singer_id
<span style="color: #7
song_ids = self.get_songs_ids(singer_url) # 得到歌手所有热门歌曲id列表
<span style="color: #8
for song_id in song_ids:
<span style="color: #9
url = "http://music.163.com/weapi/v1/resource/comments/R_SO_4_%d/?csrf_token=" % int(song_id)
<span style="color: #0
hot_comments_list = self.get_hot_comments(url)
<span style="color: #1
if(os.path.exists(singer_name)):
<span style="color: #2
self.save_to_file(hot_comments_list,u"%s/hotcomments.txt" % singer_name)
<span style="color: #3
<span style="color: #4
os.mkdir(singer_name)
<span style="color: #5
self.save_to_file(hot_comments_list,u"%s/hotcomments.txt" % singer_name)
<span style="color: #6
print(u"成功写入%s的%d首歌曲!" %(singer_name,len(song_ids)))
<span style="color: #7
<span style="color: #8
# 在一张图中绘制多个歌曲的评论分布
<span style="color: #9
# song_names_list 为多个歌曲名字的列表
<span style="color: #0
# settings 为含有字典元素的列表,每个字典含有每个子图的配置项
<span style="color: #1
def sub_plot_comments(self,song_names_list,settings,row,col):
<span style="color: #2
n = len(song_names_list) # 歌曲总数
<span style="color: #3
<span style="color: #4
<span style="color: #5
for i in range(n):
<span style="color: #6
plt.subplot(row,col,i+1)
<span style="color: #7
if(settings[i]['date_type'] == '%Y-%m-%d'):
<span style="color: #8
count_file_name = u"%s/comments_num_by_Ymd.txt" % song_names_list[i]
<span style="color: #9
<span style="color: #0
count_file_name = u"%s/comments_num_by_Ym.txt" % song_names_list[i]
<span style="color: #1
date_type = settings[i]['date_type']
<span style="color: #2
min_date_Ym = settings[i]['min_date_Ym']
<span style="color: #3
max_date_Ym = settings[i]['max_date_Ym']
<span style="color: #4
min_date_Ymd = settings[i]['min_date_Ymd']
<span style="color: #5
max_date_Ymd = settings[i]['max_date_Ymd']
<span style="color: #6
x_date,y_count = self.get_xdate_ycount(count_file_name,min_date_Ym = min_date_Ym,max_date_Ym = max_date_Ym,
<span style="color: #7
min_date_Ymd = min_date_Ymd,max_date_Ymd = max_date_Ymd,date_type = date_type)
<span style="color: #8
<span style="color: #9
x = [datetime.strptime(d, date_type).date() for d in x_date]
<span style="color: #0
# 配置横坐标为日期类型
<span style="color: #1
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%s' % date_type))
<span style="color: #2
if(date_type == '%Y-%m-%d'):
<span style="color: #3
plt.gca().xaxis.set_major_locator(mdates.DayLocator())
<span style="color: #4
<span style="color: #5
plt.gca().xaxis.set_major_locator(mdates.MonthLocator())
<span style="color: #6
plot_type = settings[i]['plot_type']
<span style="color: #7
if(plot_type == 'plot'):
<span style="color: #8
plt.plot(x,y_count,color = settings[i]['color'])
<span style="color: #9
elif(plot_type == 'bar'):
<span style="color: #0
plt.bar(x,y_count,width=settings[i]['bar_width'],color = settings[i]['color'])
<span style="color: #1
<span style="color: #2
plt.scatter(x,y_count,color = settings[i]['color'])
<span style="color: #3
plt.gcf().autofmt_xdate(rotation=settings[i]['rotation'])
# 自动旋转日期标记
<span style="color: #4
plt.title(u"网易云音乐歌曲《"
+ song_names_list[i] + u"》" + u"评论数目分布(%s到%s)" %(x[0],x[-1]),fontsize = settings[i]['fontsize'])
<span style="color: #5
plt.xlabel(u"日期")
<span style="color: #6
plt.ylabel(u"数目")
<span style="color: #7
plt.xticks(pd.date_range(x[0],x[-1],freq="%s" % settings[i]['time_distance'])) # 设置日期间隔
<span style="color: #8
plt.subplots_adjust(left=0.2, bottom=0.2, right=0.8, top=0.8,hspace=1.2,wspace=0.3)
<span style="color: #9
plt.show()
<span style="color: #0
# 得到评论列表
<span style="color: #1
def get_comments_list(self,filename):
<span style="color: #2
with codecs.open(filename,"r",encoding='utf-8') as f:
<span style="color: #3
lists = f.readlines()
<span style="color: #4
comments_list = []
<span style="color: #5
for comment in lists:
<span style="color: #6
if(re.match(r"^\d.*",comment)):
<span style="color: #7
<span style="color: #8
comments_list.append(comment.split(" ",5)[5].replace("\n",""))
<span style="color: #9
except Exception,e:
<span style="color: #0
<span style="color: #1
<span style="color: #2
comments_list.append(comment)
<span style="color: #3
return comments_list
<span style="color: #4
<span style="color: #5
# 绘制词云
<span style="color: #6
# pic_path 为词云背景图片地址
<span style="color: #7
# singer_name 为 False 时,则读取歌曲评论文件,否则读取歌手热评文件
<span style="color: #8
# isFullComments = True 时,读取全部评论,否则只读取热评
<span style="color: #9
def draw_wordcloud(self,song_name,singer_name,pic_path = "JayChou.jpg",isFullComments = True):
<span style="color: #0
if singer_name == False:
<span style="color: #1
if isFullComments == True:
<span style="color: #2
filename = u"%s/%s.txt" % (song_name,song_name) # 全部评论
<span style="color: #3
<span style="color: #4
filename = u"%s/hotcomments.txt" % song_name # 一首歌的热评
<span style="color: #5
<span style="color: #6
filename = u"%s/hotcomments.txt" % singer_name
<span style="color: #7
comments_list = self.get_comments_list(filename)
<span style="color: #8
comments_text = "".join(comments_list)
<span style="color: #9
cut_text = " ".join(jieba.cut(comments_text)) # 将jieba分词得到的关键词用空格连接成为字符串
<span style="color: #0
d = path.dirname(__file__) # 当前文件文件夹所在目录
<span style="color: #1
color_mask = imread(pic_path) # 读取背景图片
<span style="color: #2
cloud = WordCloud(font_path=path.join(d,'simsun.ttc'),background_color='white',mask=color_mask,max_words=2000,max_font_size=40)
<span style="color: #3
word_cloud = cloud.generate(cut_text) # 产生词云
<span style="color: #4
if singer_name == False:
<span style="color: #5
name = song_name
<span style="color: #6
<span style="color: #7
name = singer_name
<span style="color: #8
word_cloud.to_file(u"%s/%s.jpg" % (name,name))
<span style="color: #9
print(u"成功生成%s.jpg" % name)
<span style="color: #0
<span style="color: #1
# 对一首歌曲绘制其某一年某几个月的评论分布
<span style="color: #2
# date_lists 为要绘制的月份
<span style="color: #3
def sub_plot_months(self,song_name,DateLists,settings,row,col):
<span style="color: #4
n = len(DateLists)
<span style="color: #5
row = row # 行
<span style="color: #6
col = col # 列
<span style="color: #7
filename = u"%s/comments_num_by_Ymd.txt" % song_name
<span style="color: #8
date_lists = []
<span style="color: #9
y_count = []
<span style="color: #0
with codecs.open(filename,"r",encoding = 'utf-8') as f:
<span style="color: #1
lists = f.readlines()
<span style="color: #2
del lists[0] # 删除头部信息
<span style="color: #3
for content in lists:
<span style="color: #4
date_lists.append(content.split(" ")[0]) # 添加日期信息
<span style="color: #5
y_count.append(int(content.split(" ")[1])) # 添加数量信息
<span style="color: #6
for i in range(n):
<span style="color: #7
plt.subplot(row,col,i+1)
<span style="color: #8
x_date = [date for date in date_lists if re.match(r"%s" % DateLists[i],date)]
<span style="color: #9
y = [y_count[j] for j in range(len(y_count)) if re.match(r"%s" % DateLists[i],date_lists[j])]
<span style="color: #0
x = [datetime.strptime(d, "%Y-%m-%d").date() for d in x_date]
<span style="color: #1
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d"))
<span style="color: #2
plot_type = settings[i]['plot_type']
<span style="color: #3
if(plot_type == 'plot'):
<span style="color: #4
plt.plot(x,y,color = settings[i]['color'])
<span style="color: #5
elif(plot_type == 'bar'):
<span style="color: #6
plt.bar(x,y,width=settings[i]['bar_width'],color = settings[i]['color'])
<span style="color: #7
<span style="color: #8
plt.scatter(x,y,color = settings[i]['color'])
<span style="color: #9
plt.gcf().autofmt_xdate(rotation=settings[i]['rotation'])
# 自动旋转日期标记
<span style="color: #0
plt.title(u"《%s》%s到%s" % (song_name,x[0],x[-1]),fontsize = settings[i]['fontsize'])
<span style="color: #1
plt.xlabel(u"日期")
<span style="color: #2
plt.ylabel(u"评论数目")
<span style="color: #3
plt.xticks(pd.date_range(x[0],x[-1],freq="%s" % settings[i]['time_distance'])) # 设置日期间隔
<span style="color: #4
plt.subplots_adjust(left=0.09, bottom=0.27, right=0.89, top=0.83,hspace=0.35,wspace=0.35)
<span style="color: #5
plt.show()
<span style="color: #6
<span style="color: #7 # 绘制一首歌曲评论者相关信息的分布
<span style="color: #8
def sub_plot_commenters_info(self,song_or_singer_name):
<span style="color: #9
file_name = u"%s/commenters_info.txt" % song_or_singer_name
<span style="color: #0
with codecs.open(file_name,'r',encoding='utf-8') as f:
<span style="color: #1
info_lists = f.readlines()
<span style="color: #2
del info_lists[0] # 删除头部信息
<span style="color: #3
event_count_list = []
# 动态总数
<span style="color: #4
follow_count_list = [] # 关注总数
<span style="color: #5
fan_count_list = []
# 粉丝总数
<span style="color: #6
area_list = [] # 所在地区
<span style="color: #7
age_list = [] # 年龄
<span style="color: #8
listen_songs_num_list = [] # 累计听歌数目
<span style="color: #9
for info in info_lists:
<span style="color: #0
info.replace("\n","")
<span style="color: #1
event_count_list.append(int(info.split(" ")[1]))
<span style="color: #2
follow_count_list.append(int(info.split(" ")[2]))
<span style="color: #3
fan_count_list.append(int(info.split(" ")[3]))
<span style="color: #4
area_res= re.search(re.compile(u'.*\d (.+?-.+?) .*?|.*(未知地区).*'),info)
<span style="color: #5
if(area_res):
<span style="color: #6
if(area_res.group(1)):
<span style="color: #7
area_list.append(area_res.group(1))
<span style="color: #8
age_list.append(info.split(" ")[-2])
<span style="color: #9
listen_songs_num_list.append(int(info.split(" ")[-1]))
<span style="color: #0
event_count = [0,0,0,0]
<span style="color: #1
follow_count = [0,0,0,0,0]
<span style="color: #2
fan_count = [0,0,0,0,0]
<span style="color: #3
listen_songs_num = [0,0,0,0]
<span style="color: #4
area_count = [0,0,0,0,0,0]
<span style="color: #5
age_count = [0,0,0,0,0]
<span style="color: #6
for content in event_count_list:
<span style="color: #7
if(content &= 10):
<span style="color: #8
event_count[0] += 1
<span style="color: #9
elif(content &= 50):
<span style="color: #0
event_count[1] += 1
<span style="color: #1
elif(content &= 100):
<span style="color: #2
event_count[2] += 1
<span style="color: #3
<span style="color: #4
event_count[3] += 1
<span style="color: #5
for content in follow_count_list:
<span style="color: #6
if(content & 10):
<span style="color: #7
follow_count[0] += 1
<span style="color: #8
elif(content & 30):
<span style="color: #9
follow_count[1] += 1
<span style="color: #0
elif(content & 50):
<span style="color: #1
follow_count[2] += 1
<span style="color: #2
elif(content & 100):
<span style="color: #3
follow_count[3] += 1
<span style="color: #4
<span style="color: #5
follow_count[4] += 1
<span style="color: #6
for content in fan_count_list:
<span style="color: #7
if(content & 10):
<span style="color: #8
fan_count[0] += 1
<span style="color: #9
elif(content & 100):
<span style="color: #0
fan_count[1] += 1
<span style="color: #1
elif(content & 1000):
<span style="color: #2
fan_count[2] += 1
<span style="color: #3
elif(content & 10000):
<span style="color: #4
fan_count[3] += 1
<span style="color: #5
<span style="color: #6
follow_count[4] += 1
<span style="color: #7
area_no_repeat_list = list(set(area_list)) # 去除重复
<span style="color: #8
area_tuple = [(area,area_list.count(area)) for area in area_no_repeat_list]
<span style="color: #9
area_tuple.sort(key= lambda x:x[1],reverse=True) # 从高到低排列
<span style="color: #0
for i in range(5):
# 取出排名前4的地区
<span style="color: #1
area_count[i] = area_tuple[i][1]
<span style="color: #2
area_count[5] = sum([x[1] for x in area_tuple[5:]]) # 前5名之外的全部地区数量
<span style="color: #3
area_labels = [x[0] for x in area_tuple[0:5]] # 前5个地区的名字
<span style="color: #4
area_labels.append(u"其他地区")
<span style="color: #5
age_no_repeat_list = list(set(age_list)) # 去除重复
<span style="color: #6
age_info = [age_list.count(age) for age in age_no_repeat_list]
<span style="color: #7
for index,age_ in enumerate(age_no_repeat_list):
<span style="color: #8
if(age_ != u"未知年龄"): # 排除未知年龄
<span style="color: #9
if(int(age_) &= 17):
<span style="color: #0
age_count[0] += age_info[index] # 00后
<span style="color: #1
elif(int(age_)&=22):
<span style="color: #2
age_count[1] += age_info[index]
<span style="color: #3
elif(int(age_)&=27): # 90后
<span style="color: #4
age_count[2] += age_info[index]
<span style="color: #5
elif(int(age_)&=37): # 80后
<span style="color: #6
age_count[3] += age_info[index]
<span style="color: #7
<span style="color: #8
age_count[4] += age_info[index]
<span style="color: #9
age_labels = [u"<span style="color: #后",u"<span style="color: #后",u"<span style="color: #后",u"<span style="color: #后",u"<span style="color: #前"]
<span style="color: #0
<span style="color: #1
for content in listen_songs_num_list:
<span style="color: #2
if(content & 100):
<span style="color: #3
listen_songs_num[0] += 1
<span style="color: #4
elif(content & 1000):
<span style="color: #5
listen_songs_num[1] += 1
<span style="color: #6
elif(content & 10000):
<span style="color: #7
listen_songs_num[2] += 1
<span style="color: #8
<span style="color: #9
listen_songs_num[3] += 1
<span style="color: #0
for i in range(6):
<span style="color: #1
if(i == 0):
<span style="color: #2
title = u"%s:评论者&动态数目&分布" % song_or_singer_name
<span style="color: #3
labels = [u"<span style="color: #-10",u"<span style="color: #-50",u"<span style="color: #-100",u"<span style="color: #0以上"]
<span style="color: #4
colors = ["red","blue","yellow","green"]
<span style="color: #5
x = event_count
<span style="color: #6
plt.subplot(2,3,i+1)
<span style="color: #7
plt.pie(x,colors=colors,labels=labels,autopct="%1.1f%%")
<span style="color: #8
plt.title(title)
<span style="color: #9
# plt.legend(labels)
<span style="color: #0
elif(i == 1):
<span style="color: #1
title = u"%s:评论者&关注人数&分布" % song_or_singer_name
<span style="color: #2
labels = [u"<span style="color: #-10",u"<span style="color: #-30",u"<span style="color: #-50",u"<span style="color: #-100",u"<span style="color: #0以上"]
<span style="color: #3
colors = ["red","blue","yellow","green","white"]
<span style="color: #4
x = follow_count
<span style="color: #5
plt.subplot(2,3,i+1)
<span style="color: #6
plt.pie(x,colors=colors,labels=labels,autopct="%1.1f%%")
<span style="color: #7
plt.title(title)
<span style="color: #8
# plt.legend(labels)
<span style="color: #9
elif(i == 2):
<span style="color: #0
title = u"%s:评论者&粉丝人数&分布" % song_or_singer_name
<span style="color: #1
labels = [u"<span style="color: #-10",u"<span style="color: #-100",u"<span style="color: #0-1000",u"<span style="color: #00-10000",u"<span style="color: #000以上"]
<span style="color: #2
colors = ["red","blue","yellow","green","white"]
<span style="color: #3
x = fan_count
<span style="color: #4
plt.subplot(2,3,i+1)
<span style="color: #5
plt.pie(x,colors=colors,labels=labels,autopct="%1.1f%%")
<span style="color: #6
plt.title(title)
<span style="color: #7
# plt.legend(labels)
<span style="color: #8
elif(i == 3):
<span style="color: #9
title = u"%s:评论者&地区&分布" % song_or_singer_name
<span style="color: #0
colors = ["red","blue","yellow","green","white","purple"]
<span style="color: #1
x = area_count
<span style="color: #2
plt.subplot(2,3,i+1)
<span style="color: #3
plt.pie(x,colors=colors,labels=area_labels,autopct="%1.1f%%")
<span style="color: #4
plt.title(title)
<span style="color: #5
# plt.legend(area_labels,loc='upper center', bbox_to_anchor=(0.1,0.9),ncol=1,fancybox=True,shadow=True)
<span style="color: #6
elif(i == 4):
<span style="color: #7
title = u"%s:评论者&年龄&分布" % song_or_singer_name
<span style="color: #8
colors = ["red","blue","yellow","green","white"]
<span style="color: #9
x = age_count
<span style="color: #0
plt.subplot(2,3,i+1)
<span style="color: #1
plt.pie(x,colors=colors,labels=age_labels,autopct="%1.1f%%")
<span style="color: #2
plt.title(title)
<span style="color: #3
# plt.legend(age_labels)
<span style="color: #4
<span style="color: #5
title = u"%s:评论者&累计听歌&分布" % song_or_singer_name
<span style="color: #6
labels = [u"<span style="color: #-100",u"<span style="color: #0-1000",u"<span style="color: #00-10000",u"<span style="color: #000以上"]
<span style="color: #7
colors = ["red","blue","yellow","green"]
<span style="color: #8
x = listen_songs_num
<span style="color: #9
plt.subplot(2,3,i+1)
<span style="color: #0
plt.pie(x,colors=colors,labels=labels,autopct="%1.1f%%")
<span style="color: #1
plt.title(title)
<span style="color: #2
# plt.legend(labels)
<span style="color: #3
plt.tight_layout()
<span style="color: #4
plt.show()
<span style="color: #5
<span style="color: #6
# sub_plot_months 测试
<span style="color: #7
def sub_plot_months_test(self):
<span style="color: #8
song_name = u"越长大越孤单"
<span style="color: #9
<span style="color: #0
<span style="color: #1
settings_dict = {
<span style="color: #2
"plot_type":"plot",
<span style="color: #3
"color":"g",
<span style="color: #4
"bar_width":0.8,
<span style="color: #5
"fontsize":10,
<span style="color: #6
"rotation":50,
<span style="color: #7
"time_distance":"<span style="color: #D"
<span style="color: #8
<span style="color: #9
settings = []
<span style="color: #0
DateLists = ['<span style="color: #16-04','<span style="color: #16-05','<span style="color: #16-06','<span style="color: #16-07','<span style="color: #16-08','<span style="color: #16-09','<span style="color: #16-10','<span style="color: #16-11','<span style="color: #16-12','<span style="color: #17-01','<span style="color: #17-02','<span style="color: #17-03']
<span style="color: #1
for i in range(len(DateLists)):
<span style="color: #2
settings.append(settings_dict)
<span style="color: #3
self.sub_plot_months(song_name,DateLists,settings,row=row,col=col)
<span style="color: #4
<span style="color: #5
# 绘制subplot 测试
<span style="color: #6
def subplot_test(self):
<span style="color: #7
song_names_list = [u"七里香",u"不要再孤单",u"All Too Well",u"刚好遇见你"]
<span style="color: #8
settings_dict = {"date_type":"%Y-%m-%d",
<span style="color: #9
"plot_type":"bar",
<span style="color: #0
"fontsize":12,
<span style="color: #1
"color":"r",
<span style="color: #2
"bar_width":0.4,
<span style="color: #3
"rotation":50,
<span style="color: #4
"time_distance":"<span style="color: #D",
<span style="color: #5
"min_date_Ymd":"<span style="color: #17-03-01",
<span style="color: #6
"max_date_Ymd":"<span style="color: #17-12-31",
<span style="color: #7
"min_date_Ym":"<span style="color: #13-01",
<span style="color: #8
"max_date_Ym":"<span style="color: #17-12"
<span style="color: #9
<span style="color: #0
settings = []
<span style="color: #1
for i in range(len(song_names_list)):
<span style="color: #2
settings.append(settings_dict)
<span style="color: #3
<span style="color: #4
<span style="color: #5
self.sub_plot_comments(song_names_list,settings,row=row,col = col)
<span style="color: #6
<span style="color: #7
# plot_comments 函数测试
<span style="color: #8
def plot_comments_test(self):
<span style="color: #9
song_name = u"我从崖边跌落"
<span style="color: #0
settings = {
<span style="color: #1
"comment_type":False,
<span style="color: #2
"date_type":"%Y-%m-%d",
<span style="color: #3
"plot_type":"plot",
<span style="color: #4
"bar_width":0.8,
<span style="color: #5
"rotation":20,
<span style="color: #6
"color":"purple",
<span style="color: #7
"pie_colors":["blue","red","coral","green","yellow"],
<span style="color: #8
"auto_pct":'%1.1f%%',
<span style="color: #9
"expl" :[0,0,0.1,0.3],
# 离开圆心的距离
<span style="color: #0
"time_distance":"<span style="color: #D",
<span style="color: #1
"min_date_Ymd":"<span style="color: #13-12-01",
<span style="color: #2
"max_date_Ymd":"<span style="color: #17-12-31",
<span style="color: #3
"min_date_Ym":"<span style="color: #13-01",
<span style="color: #4
"max_date_Ym":"<span style="color: #17-12"
<span style="color: #5
<span style="color: #6
self.plot_comments(song_name,settings)
<span style="color: #7
<span style="color: #8
<span style="color: #9 if __name__ == '__main__':
<span style="color: #0
Processor = NetCloudProcessor()
<span style="color: #1
Processor.plot_comments_test()
注:上面的代码无法直接运行,因为绘图时缺少必要的文件(即函数create_all_necessary_files产生的与歌曲名字或者歌手同名的文件夹),大家可以去百度云下载我已经抓取过的数据(地址:http://pan.baidu.com/s/1slS55gx)或者自行抓取。有任何问题,欢迎大家的指教。
阅读(...) 评论()

我要回帖

更多关于 微博刷转发评论 的文章

 

随机推荐