【项目预览】
【创作背景】
可能因为我的名字叫云云,我一直对词云图情有独钟。曾经找到过一个网站,免费生成各式各样的词云图(https://wordart.com/),我玩的废寝忘食。但这是一个外国网站,是针对英文设计的,无法进行中文分词(即把句子拆分成词语,英文不存在这个问题,英文原本就是用空格隔开的单词构成的)。如果要手动进行中文分词,工作量之大让人望而生畏。
学了python之后,我找到了结巴分词器,“把我写的文章画成图”的想法又蠢蠢欲动起来。
一开始,我只会简单调用结巴分词器,输入一段文字,分词,然后复制分好的词,粘贴到刚才提到的词云图网站,让网站给我画图。虽然可行,但略显麻烦,而且网站能接受的输入文本大小有限:一次粘贴太多,就装不下了。
后来,等我跟着课程一路学完了爬虫,数据分析,又重新想起这个项目的时候,我发现我自己已经有能力做出“一条龙服务”的程序了!
【功能设想】
这个项目的功能我是一边做一边完善的。
版本1.0:我把“爬歌词”和“绘制词云图”组合起来,画出指定歌曲的词云图。这个图可以用来在搞团建的时候做游戏:展示图片,大家猜歌名。
版本2.0:我把“爬歌手评论”和“绘制词云图”结合起来,画出了指定歌手的热评词云图。如果说爬歌词只具有娱乐意义,那么爬评论,就有舆情调查的味道了。
版本3.0:我一口气爬了9个我喜欢的歌手的评论,画了9张图,然后发现:这些图里最大的词(频次最高的词)居然都是一样的:
“有时候,我们喜欢一个自己,就是因为知道真的不是什么”(噗哈哈哈哈,这些词造句还挺喜感的)
每个歌手的热评词云图都被这几个最热的公共热词撑满了,这样画出来的图,似乎意义也不大。于是我想:减掉公共热词,找出每个歌手的独特热词吧!这样,应该能找出该歌手在歌迷心中的特点。于是,这个项目被命名为:寻找独特词。
【功能实现】
1,【爬虫】爬歌曲评论,生成指定歌手的热门歌曲评论txt(每个歌手我爬了50首歌,每首歌20条最热门的评论)。
2,【Jieba, Pandas】打开txt文件,用结巴分词器分词,用pandas分类汇总+排序,制成该歌手评论热词的词频excel。
3,【pandas】将9个歌手的词频excel合并,找出公共热词。为方便以后使用,制成公共热词excel:《zong.xlsx》。
4,【pandas】用每个人的词频库减去公共热词,得到每个歌手的独特词词频。
5,【WordCloud】画独特词词云图。
【完工感受】
这个项目做完我感觉我厉害极了,自我成就感爆棚。然后我开始在优快云上面到处晃荡,发现了无穷无尽的有趣的项目。。。我决定,我也开个博客,把我的编程生涯里有趣的项目记录下来。
最后,学无止境!
【完整代码】
(此代码用到了zong.xlsx文件。此文件一共就2列,你可以自己建一个。)
词语 | 总频次 |
喜欢 | 4619 |
我们 | 4531 |
一个 | 4389 |
自己 | 3384 |
首歌 | 3021 |
没有 | 2664 |
时候 | 2400 |
就是 | 2381 |
知道 | 2232 |
还是 | 1903 |
真的 | 1877 |
不是 | 1858 |
因为 | 1831 |
现在 | 1730 |
可以 | 1590 |
一起 | 1552 |
什么 | 1525 |
一直 | 1362 |
那个 | 1227 |
这个 | 1209 |
那么 | 1191 |
世界 | 1146 |
一样 | 1087 |
但是 | 1079 |
这样 | 1037 |
希望 | 1008 |
开始 | 930 |
import jieba,re,requests,time,os
import pandas as pd
import pyecharts.options as opts
from pyecharts.charts import WordCloud
#--------------------------第一步,爬取评论---------------------------------------
url1= 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp'
url2 = 'https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg'
headers = {'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
print('\n《寻找独特词》,找出某歌手(某歌曲)的评论当中独特的热词。')
print('\n制作:云云\n日期:2021-5-20')
try:
os.makedirs('./热评词云图')
except:
pass
while True:
cho=input('\n\n第一步,爬取评论:输入1-按歌手查找。输入2-按歌曲查找:')
if cho=='1':
key=input('\n输入歌手名:')
page_set=int(input('\n需要爬取多少页的歌曲(每页10首歌,支持1-5页):'))
filename='./热评词云图/{}-歌曲评论.txt'.format(key)
f=open(filename,'a',encoding='utf-8')
num=0
songpool=[]
for page in range(page_set):
params1 = {
'ct':'24',
'qqmusic_ver': '1298',
'new_json':'1',
'remoteplace':'sizer.yqq.song_next',
'searchid':'59091538798969282',
't':'0',
'aggr':'1',
'cr':'1',
'catZhida':'1',
'lossless':'0',
'flag_qc':'0',
'p':page+1,
'n':'10',
'w':key,
'g_tk':'5381',
'loginUin':'0',
'hostUin':'0',
'format':'json',
'inCharset':'utf8',
'outCharset':'utf-8',
'notice':'0',
'platform':'yqq.json',
'needNewCode':'0'
}
res1=requests.get(url1,params=params1,headers=headers)
json1=res1.json()
list1=json1['data']['song']['list']
for i in list1:
topid=i['id']
songname=i['title']
if songname not in songpool:
songpool.append(songname)
num+=1
print('正在获取第{}首歌-《{}》的评论...'.format(num,songname))
time.sleep(0.5)
for i in range(2):
params2 = {
'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':'1',
'topid':topid,
'cmd':'6',
'needmusiccrit':'0',
'pagenum':str(i+1),
'pagesize':'15',
'lasthotcommentid':'song_102065756_3202544866_44059185',
'domain':'qq.com',
'ct':'24',
'cv':'10101010'
}
try:
res2 = requests.get(url2,params=params2,headers=headers)
json2 = res2.json()
list2 = json2['comment']['commentlist']
for j in list2:
comment=j['rootcommentcontent']
f.write(comment)
except:
pass
elif cho=='2':
key=input('\n输入歌曲名:')
filename='./热评词云图/{}-歌曲评论.txt'.format(key)
f=open(filename,'a',encoding='utf-8')
params1 = {
'ct':'24',
'qqmusic_ver': '1298',
'new_json':'1',
'remoteplace':'sizer.yqq.song_next',
'searchid':'59091538798969282',
't':'0',
'aggr':'1',
'cr':'1',
'catZhida':'1',
'lossless':'0',
'flag_qc':'0',
'p':1,
'n':'10',
'w':key,
'g_tk':'5381',
'loginUin':'0',
'hostUin':'0',
'format':'json',
'inCharset':'utf8',
'outCharset':'utf-8',
'notice':'0',
'platform':'yqq.json',
'needNewCode':'0'
}
res1=requests.get(url1,params=params1,headers=headers)
json1=res1.json()
topid=json1['data']['song']['list'][0]['id']
songname=json1['data']['song']['list'][0]['title']
print('正在获取《{}》的评论...'.format(songname))
for i in range(2):
params2 = {
'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':'1',
'topid':topid,
'cmd':'6',
'needmusiccrit':'0',
'pagenum':str(i+1),
'pagesize':'15',
'lasthotcommentid':'song_102065756_3202544866_44059185',
'domain':'qq.com',
'ct':'24',
'cv':'10101010'
}
try:
res2 = requests.get(url2,params=params2,headers=headers)
json2 = res2.json()
list2 = json2['comment']['commentlist']
for j in list2:
comment=j['rootcommentcontent']
f.write(comment)
except:
pass
print('\n'+filename+'写入已完成。')
f.close()
time.sleep(1)
#--------------------------第二步,生成热词词频---------------------------
fre_set=int(input('\n\n第二步,生成热词:输入用于绘制词云图的词频下限(不知道就写1):'))
with open (filename,'r',encoding='utf-8') as f:
content=f.read()
#stop1 = "[^0-9A-Za-z\u4e00-\u9fa5]" 仅去掉符号
stop1 = "[^\u4e00-\u9fa5]" # 去掉符号,数字,字母(只保留中文)
content=re.sub(stop1,'',content)
stop2=input('\n输入需要手动过滤掉的所有词语(建议输入歌手名字、昵称),用空格隔开(选填):')
alist=stop2.split()
for i in alist:
content=content.replace(i,'')
#print('\n绘制内容节选:\n'+content[:100])
seg_list=jieba.cut(content,cut_all=False)
df=pd.DataFrame(seg_list)
df.columns=['词语']
df=df[df['词语'].str.len()>1] # 去掉所有单字(遗憾,去掉了“爱”等热词)
df['频次']=1
df=df.groupby('词语')['频次'].sum()
data=pd.DataFrame()
data['词语']=df.index
data['频次']=df.values
data=data[data['频次']>fre_set]
data=data.sort_values(by='频次',ascending=False)
print(key+'-歌曲评论-热词词频:')
print(data.head(10))
time.sleep(1)
#-----------------------------第三段------------------------------------
print('\n第三步:生成歌手/歌曲独特词的词云图...')
name=key
zong=pd.read_excel('zong.xlsx')
#filename=name+'-歌曲评论-词频.xlsx'
htmlname='./热评词云图/{}-独特词-词云图.html'.format(name)
uniexcelname='./热评词云图/{}-独特词-词频.xlsx'.format(name)
chartname='{}-独特词-词云图'.format(name)
df=data
df=pd.merge(df,zong,how='outer')
df=df[df['总频次'].isna()]
df=df[df.index<100]
df.index=df['词语']
try:
df=df.drop([name],axis=0)
except:
pass
print('\n'+name+'-独特词-词频:')
print(df.head(10))
name=df['词语']
value=df['频次']
data1=[z for z in zip(name,value)]
chart=WordCloud()
chart.add('频次',data_pair=data1,shape='circle',word_size_range=[10,100])
chart.set_global_opts(title_opts=opts.TitleOpts(title=chartname))
chart.render(htmlname)
#df.to_excel(uniexcelname,index=False)
time.sleep(1)
print('\n词云图绘制成功。')
again=input('\n大功告成!如需继续画图请按1,退出请按回车:')
if again!='1':
break