【云云怪】第8个项目:寻找歌手的独特词

本文介绍了一个Python项目,通过爬虫获取歌手评论,利用结巴分词和Pandas分析,生成词云图,最终找出每位歌手的独特热词,揭示歌迷心中的歌手特色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【项目预览】

【创作背景】

可能因为我的名字叫云云,我一直对词云图情有独钟。曾经找到过一个网站,免费生成各式各样的词云图(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列,你可以自己建一个。)

zong.xlsx
词语总频次
喜欢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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值