爬取热门歌手及相关数据分析

一、选题的背景

音乐是绝大部分人不可获取的生活中的一部分,每个人都有自己喜欢的歌曲,都有自己喜欢的歌手,对许多歌手都没有了解。本课题爬取几位热门歌手的歌曲歌单;选其一首进行数据分析,更清楚的了解此歌曲。通过分析更好的了解歌手以及歌曲信息。

二、主题式网络爬虫设计方案

1.主题式网络爬虫名称

爬取热门歌手歌单

2.主题式网络爬虫爬取的内容与数据特征分析

爬取该音乐平台热门歌曲,对其单曲相关内容进行分析

3.主题式网络爬虫设计方案概述

分析网页源代码,找出所需要的歌曲。对需要的歌曲的数据进行清理。

三、主题页面的结构特征分析

1.主题页面的结构与特征分析

 

https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60997426243444153&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w=%E9%82%93%E7%B4%AB%E6%A3%8B&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0%27

 

https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60997426243444153&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w=%E9%82%93%E7%B4%AB%E6%A3%8B&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0%27

 

 

 

 

 

https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60997426243444153&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w=%E9%82%93%E7%B4%AB%E6%A3%8B&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0%27

 2.Htmls 页面解析

如上图所示我们可以找到不同音乐的浏览地址,发现所需要的数据存在于该链接的body 标签下的div标签,可以发现我们所需要的内容就在这里。其他歌曲也是相同的原理。

3.节点(标签)查找方法与遍历方法

通过标签提示去寻找我们所需要的内容。

(四)、网络爬虫程序设计

1.数据爬取与采集

1):所需要的库

 1  # 导入包
 2 import pandas as pd
 3 import time
 4 import requests
 5 import json
 6 from fake_useragent import UserAgent
 7 import jieba
 8 import stylecloud
 9 from pyecharts.charts import Pie, Bar, Map, Line, WordCloud, Page
10 from pyecharts import options as opts
11 from pyecharts.globals import SymbolType

截图展示:

 

 

挑选三位歌手歌单爬取与展示

邓紫棋

源码:

 

 1 import requests
 2 # 引用requests库
 3 res_music = requests.get('https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60997426243444153&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w=%E9%82%93%E7%B4%AB%E6%A3%8B&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0%27')
 4 # 调用get方法,下载这个字典
 5 json_music = res_music.json()
 6 # 使用json()方法,将response对象,转为列表/字典
 7 list_music = json_music['data']['song']['list']
 8 # 一层一层地取字典,获取歌单列表
 9 for music in list_music:
10 # list_music是一个列表,music是它里面的元素
11     print(music['name'])
12     # 以name为键,查找歌曲名

 

截图展示:

 

 

 周杰伦

 1 import requests
 2 # 引用requests库
 3 res_music = requests.get('https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60997426243444153&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w=%E5%91%A8%E6%9D%B0%E4%BC%A6&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0%27')
 4 # 调用get方法,下载这个字典
 5 json_music = res_music.json()
 6 # 使用json()方法,将response对象,转为列表/字典
 7 list_music = json_music['data']['song']['list']
 8 # 一层一层地取字典,获取歌单列表
 9 for music in list_music:
10 # list_music是一个列表,music是它里面的元素
11     print(music['name'])
12     # 以name为键,查找歌曲名

 

 

 

 汪苏泷

源码:

 1 import requests
 2 # 引用requests库
 3 res_music = requests.get('https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60997426243444153&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w=%E6%B1%AA%E8%8B%8F%E6%B3%B7&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0%27')
 4 # 调用get方法,下载这个字典
 5 json_music = res_music.json()
 6 # 使用json()方法,将response对象,转为列表/字典
 7 list_music = json_music['data']['song']['list']
 8 # 一层一层地取字典,获取歌单列表
 9 for music in list_music:
10 # list_music是一个列表,music是它里面的元素
11     print(music['name'])
12     # 以name为键,查找歌曲名

截图展示:

 

 选取歌曲《mojito》对数据进行清理

源码:

 1  # 导入包
 2 import pandas as pd
 3 import time
 4 import requests
 5 import json
 6 from fake_useragent import UserAgent
 7 
 8 
 9 def get_qq_comment(page_num):
10     # 存储数据
11     df_all = pd.DataFrame()
12 
13     for i in range(page_num):
14         # 打印进度
15         print('我正在获取第{}页的信息'.format(i))
16 
17         # 获取URL
18         url = 'https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg?g_tk_new_20200303=5381&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=GB2312&notice=0&platform=yqq.json&needNewCode=0&cid=205360772&reqtype=2&biztype=2&topid=12924001&cmd=8&needmusiccrit=0&pagenum={}&pagesize=25'.format(i)
19 
20         # 添加headers
21         headers = {
22             'user-agent': UserAgent().random
23         }
24 
25         # 发起请求
26         try:
27             r = requests.get(url, headers=headers)
28         except Exception as e:
29             print(e)
30             continue
31 
32         # 解析网页
33         json_data = json.loads(r.text)
34 
35         # 获取数据
36         comment_list = json_data['comment']['commentlist']
37 
38         # 昵称
39         nick_name = [i.get('nick') for i in comment_list]
40         # 评论内容
41         content = [i.get('rootcommentcontent') for i in comment_list]
42         # 评论时间
43         comment_time = [i.get('time') for i in comment_list]
44         # 点赞数
45         praise_num = [i.get('praisenum') for i in comment_list]
46 
47         # 存储数据
48         df = pd.DataFrame({
49             'nick_name': nick_name,
50             'content': content,
51             'comment_time': comment_time,
52             'praise_num': praise_num
53         })
54 
55         # 追加数据
56         df_all = df_all.append(df, ignore_index=True)
57 
58         # 休眠一秒
59         time.sleep(1)
60 
61     return df_all
62 
63 
64 # 运行函数
65 df = get_qq_comment(page_num=5) 
66 
67 df.to_excel('D:\\1.xlsx',index = False)

截图展示

 

df = pd.read_excel('D:\\1.xlsx')
df

截图展示

 

 

 源码: 1 print(df.duplicated().sum())2 print(df.isnull().sum()) 

 

截图展示:

 

源码:

  1 df['comment_time'] 

截图展示:

 

 源码:

1 def transform_time(time_second):
2     time_array = time.localtime(time_second)
3     otherStyleTime = time.strftime('%Y-%m-%d %H:%M:%S', time_array) 
4     return otherStyleTime
5 
6 # 时间数据处理
7 df['comment_time'] = df['comment_time'].apply(lambda x: transform_time(x))

截图展示:

 

 

源码:

1 import re
2 pattern = re.compile(r'\[em\](.*?)\[/em\]')
3 df['content'] = df.content.str.replace(pattern, '')
4 df.head()

截图展示:

源码:

 1 comment_num = df.comment_time.str.split(':').str[0].value_counts().sort_index() 

截图展示:

 

 

源码:

 1 # 去掉年份
 2 x_line1 = [i.replace('2020-','') for i in comment_num.index.to_list()] 
 3 '''
 4 ['06-20 14',
 5  '06-20 15',
 6  '06-20 16',
 7  '06-20 17',
 8  '06-20 18',
 9  ...
10 '''
11 # 这个时点评论人数
12 y_line1 = comment_num.values.tolist()
13 # [3, 15, 6, 15, 11, 12, 4, 10, 5, 10, 9, 1, 3, 1, 1, 1, 3, 7, 7, 1]
14 # 去掉年份
15 x_line1 = [i.replace('2020-','') for i in comment_num.index.to_list()] 
16 '''
17 ['06-20 14',
18  '06-20 15',
19  '06-20 16',
20  '06-20 17',
21  '06-20 18',
22  ...
23 '''
24 # 这个时点评论人数
25 y_line1 = comment_num.values.tolist()
26 # [3, 15, 6, 15, 11, 12, 4, 10, 5, 10, 9, 1, 3, 1, 1, 1, 3, 7, 7, 1]
27 
28  # 去掉年份
29 x_line1 = [i.replace('2020-','') for i in comment_num.index.to_list()] 
30 x_line1
31 
32 # 这个时点评论人数
33 y_line1 = comment_num.values.tolist()
34 y_line1

4.数据分析与可视化

对歌曲mojito进行分析

 1 c = (
 2     Line() #初始化
 3     .add_xaxis(x_line1) # X轴
 4     # Y轴
 5     .add_yaxis('',  # 系列名称
 6                 y_line1,# 系列数据
 7                 # 标记点配置项
 8                 markpoint_opts=opts.MarkPointOpts(data=[
 9                     opts.MarkPointItem(type_='max', name='最大值'),# 标记最大值
10                     opts.MarkPointItem(type_='min', name='最小值') # 标记最小值
11                 ])) 
12     # 全局配置项
13     .set_global_opts(
14             # 标题设置
15             title_opts=opts.TitleOpts('Mojito评论人数走势图'), 
16             # 轴标签设置
17             xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate='30')), # 标签旋转 
18             ) 
19     # 系统配置项
20     .set_series_opts(
21     # 标签配置项
22     label_opts=opts.LabelOpts(is_show=False),  # 不显示标签
23     # 线配置项
24     linestyle_opts=opts.LineStyleOpts(width=3)) # 线宽3
25     .render("line_base.html")
26  )

截至2021.12.22

6.数据持久化

评论存储在 D:\\1.xlsx

 

 

对我喜欢的歌手的粉丝数进行分块(数据来源微博)

源码:

 1 import csv
 2 import matplotlib
 3 import matplotlib.pyplot as plt
 4 import numpy as np
 5 import pandas as pd
 6 def fs_Dis():#统计胜率分布
 7     pr = pd.read_csv('E:/粉丝数分级.csv')
 8     pr1 = pd.read_csv('E:/粉丝数分级.csv', low_memory=False)
 9     print("粉丝数量分级:")
10     print()
11     fs = []
12     for i in pr['Fans several']:
13          fs.append(i)
14     fs1=[]
15     fs2=[]
16     fs3=[]
17     fs4=[]
18     for i in fs:
19         if  0<i<1000:
20             fs1.append(i)
21         elif 1000<i<2000:
22             fs2.append(i)
23         elif 2000<i<5000:
24             fs3.append(i)
25         elif 5000<i:
26             fs4.append(i)
27    
28 
29 
30 
31 
32     index=['0-1000','1000-2000','2000-5000','5000+']
33     values=[len(fs1),len(fs2),len(fs3),len(fs4)]
34     plt.bar(index,values)
35     plt.show()
36 
37 
38 if __name__=="__main__":
39     fs_Dis()

截图展示:

 

 全部代码:

  1 # 导入包
  2 import pandas as pd
  3 import time
  4 import requests
  5 import json
  6 from fake_useragent import UserAgent
  7 import jieba
  8 import stylecloud
  9 from pyecharts.charts import Pie, Bar, Map, Line, WordCloud, Page
 10 from pyecharts import options as opts
 11 from pyecharts.globals import SymbolType
 12 
 13 res_music = requests.get('https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60997426243444153&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w=%E6%B1%AA%E8%8B%8F%E6%B3%B7&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0%27')
 14 # 调用get方法,下载这个字典
 15 json_music = res_music.json()
 16 # 使用json()方法,将response对象,转为列表/字典
 17 list_music = json_music['data']['song']['list']
 18 # 一层一层地取字典,获取歌单列表
 19 for music in list_music:
 20 # list_music是一个列表,music是它里面的元素
 21     print(music['name'])
 22 # 以name为键,查找歌曲名
 23 
 24 res_music = requests.get('https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60997426243444153&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w=%E5%91%A8%E6%9D%B0%E4%BC%A6&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0%27')
 25 # 调用get方法,下载这个字典
 26 json_music = res_music.json()
 27 # 使用json()方法,将response对象,转为列表/字典
 28 list_music = json_music['data']['song']['list']
 29 # 一层一层地取字典,获取歌单列表
 30 for music in list_music:
 31 # list_music是一个列表,music是它里面的元素
 32     print(music['name'])
 33 # 以name为键,查找歌曲名
 34 
 35 res_music = requests.get('https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60997426243444153&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w=%E9%82%93%E7%B4%AB%E6%A3%8B&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0%27')
 36 # 调用get方法,下载这个字典
 37 json_music = res_music.json()
 38 # 使用json()方法,将response对象,转为列表/字典
 39 list_music = json_music['data']['song']['list']
 40 # 一层一层地取字典,获取歌单列表
 41 for music in list_music:
 42 # list_music是一个列表,music是它里面的元素
 43     print(music['name'])
 44 # 以name为键,查找歌曲名
 45 
 46 
 47 def get_qq_comment(page_num):
 48     # 存储数据
 49     df_all = pd.DataFrame()
 50 
 51     for i in range(page_num):
 52         # 打印进度
 53         print('我正在获取第{}页的信息'.format(i))
 54 
 55         # 获取URL
 56         url = 'https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg?g_tk_new_20200303=5381&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=GB2312&notice=0&platform=yqq.json&needNewCode=0&cid=205360772&reqtype=2&biztype=2&topid=12924001&cmd=8&needmusiccrit=0&pagenum={}&pagesize=25'.format(i)
 57 
 58         # 添加headers
 59         headers = {
 60             'user-agent': UserAgent().random
 61         }
 62 
 63         # 发起请求
 64         try:
 65             r = requests.get(url, headers=headers)
 66         except Exception as e:
 67             print(e)
 68             continue
 69 
 70         # 解析网页
 71         json_data = json.loads(r.text)
 72 
 73         # 获取数据
 74         comment_list = json_data['comment']['commentlist']
 75 
 76         # 昵称
 77         nick_name = [i.get('nick') for i in comment_list]
 78         # 评论内容
 79         content = [i.get('rootcommentcontent') for i in comment_list]
 80         # 评论时间
 81         comment_time = [i.get('time') for i in comment_list]
 82         # 点赞数
 83         praise_num = [i.get('praisenum') for i in comment_list]
 84 
 85         # 存储数据
 86         df = pd.DataFrame({
 87             'nick_name': nick_name,
 88             'content': content,
 89             'comment_time': comment_time,
 90             'praise_num': praise_num
 91         })
 92 
 93         # 追加数据
 94         df_all = df_all.append(df, ignore_index=True)
 95 
 96         # 休眠一秒
 97         time.sleep(1)
 98 
 99     return df_all
100 
101 
102 # 运行函数
103 df = get_qq_comment(page_num=5)
104 
105 df.to_excel('D:\\1.xlsx',index = False)
106 
107 df = pd.read_excel('D:\\1.xlsx')
108 
109 df
110 
111 print(df.duplicated().sum())  # 0
112 
113 print(df.isnull().sum())
114 
115 df['comment_time']
116 
117 def transform_time(time_second):
118     time_array = time.localtime(time_second)
119     otherStyleTime = time.strftime('%Y-%m-%d %H:%M:%S', time_array)
120     return otherStyleTime
121 
122 # 时间数据处理
123 df['comment_time'] = df['comment_time'].apply(lambda x: transform_time(x))
124 
125 import re
126 pattern = re.compile(r'\[em\](.*?)\[/em\]')
127 df['content'] = df.content.str.replace(pattern, '')
128 df.head()
129 
130 # 去掉年份
131 x_line1 = [i.replace('2020-','') for i in comment_num.index.to_list()]
132 '''
133 ['06-20 14',
134  '06-20 15',
135  '06-20 16',
136  '06-20 17',
137  '06-20 18',
138  ...
139 '''
140 # 这个时点评论人数
141 y_line1 = comment_num.values.tolist()
142 # [3, 15, 6, 15, 11, 12, 4, 10, 5, 10, 9, 1, 3, 1, 1, 1, 3, 7, 7, 1]
143 # 去掉年份
144 x_line1 = [i.replace('2020-','') for i in comment_num.index.to_list()]
145 '''
146 ['06-20 14',
147  '06-20 15',
148  '06-20 16',
149  '06-20 17',
150  '06-20 18',
151  ...
152 '''
153 # 这个时点评论人数
154 y_line1 = comment_num.values.tolist()
155 # [3, 15, 6, 15, 11, 12, 4, 10, 5, 10, 9, 1, 3, 1, 1, 1, 3, 7, 7, 1]
156 
157  # 去掉年份
158 x_line1 = [i.replace('2020-','') for i in comment_num.index.to_list()]
159 x_line1
160 
161 # 这个时点评论人数
162 y_line1 = comment_num.values.tolist()
163 y_line1
164 
165 c = (
166     Line() #初始化
167     .add_xaxis(x_line1) # X轴
168     # Y轴
169     .add_yaxis('',  # 系列名称
170                 y_line1,# 系列数据
171                 # 标记点配置项
172                 markpoint_opts=opts.MarkPointOpts(data=[
173                     opts.MarkPointItem(type_='max', name='最大值'),# 标记最大值
174                     opts.MarkPointItem(type_='min', name='最小值') # 标记最小值
175                 ]))
176     # 全局配置项
177     .set_global_opts(
178             # 标题设置
179             title_opts=opts.TitleOpts('Mojito评论人数走势图'),
180             # 轴标签设置
181             xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate='30')), # 标签旋转
182             )
183     # 系统配置项
184     .set_series_opts(
185     # 标签配置项
186     label_opts=opts.LabelOpts(is_show=False),  # 不显示标签
187     # 线配置项
188     linestyle_opts=opts.LineStyleOpts(width=3)) # 线宽3
189     .render("line_base.html")
190  )
191 import csv
192 import matplotlib
193 import matplotlib.pyplot as plt
194 import numpy as np
195 import pandas as pd
196 def fs_Dis():#统计胜率分布
197     pr = pd.read_csv('E:/粉丝数分级.csv')
198     pr1 = pd.read_csv('E:/粉丝数分级.csv', low_memory=False)
199     print("粉丝数量分级:")
200     print()
201     fs = []
202     for i in pr['Fans several']:
203          fs.append(i)
204     fs1=[]
205     fs2=[]
206     fs3=[]
207     fs4=[]
208     for i in fs:
209         if  0<i<1000:
210             fs1.append(i)
211         elif 1000<i<2000:
212             fs2.append(i)
213         elif 2000<i<5000:
214             fs3.append(i)
215         elif 5000<i:
216             fs4.append(i)
217    
218 
219 
220 
221 
222     index=['0-1000','1000-2000','2000-5000','5000+']
223     values=[len(fs1),len(fs2),len(fs3),len(fs4)]
224     plt.bar(index,values)
225     plt.show()
226 
227 
228 if __name__=="__main__":
229     fs_Dis()

 

五、总结

1.经过对主题数据的分析与可视化,可以得到哪些结论?是否达到预期的目标?

从这次歌曲爬取中,可以获取不同歌手的不同歌曲,还对部分跟歌曲进行了分析,分析评论的人数走势图。评论的人数没有根据时间变化。能够达到预期分析目标。

 

2.在完成此设计过程中,得到哪些收获?以及要改进的建议?

通过这次对音乐的爬取让我更加深刻的了解到音乐的魅力,对于音乐的热爱也越来越深,也让我感受到音乐与代码结合的魅力。通过本次爬虫设计也让我学到了许多,我明白了自己的技能水平还有待提高。在以后的爬虫课题制作可以爬取更广泛的覆盖面对外国歌手进行分析。

posted @ 2021-12-28 13:13  小天才2121  阅读(424)  评论(0)    收藏  举报