爬取热门歌手及相关数据分析
一、选题的背景
音乐是绝大部分人不可获取的生活中的一部分,每个人都有自己喜欢的歌曲,都有自己喜欢的歌手,对许多歌手都没有了解。本课题爬取几位热门歌手的歌曲歌单;选其一首进行数据分析,更清楚的了解此歌曲。通过分析更好的了解歌手以及歌曲信息。
二、主题式网络爬虫设计方案
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¬ice=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¬ice=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¬ice=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¬ice=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¬ice=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¬ice=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¬ice=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¬ice=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¬ice=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¬ice=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¬ice=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.在完成此设计过程中,得到哪些收获?以及要改进的建议?
通过这次对音乐的爬取让我更加深刻的了解到音乐的魅力,对于音乐的热爱也越来越深,也让我感受到音乐与代码结合的魅力。通过本次爬虫设计也让我学到了许多,我明白了自己的技能水平还有待提高。在以后的爬虫课题制作可以爬取更广泛的覆盖面对外国歌手进行分析。


浙公网安备 33010602011771号