【原创】python词云分析陈粒和赵雷

未经同意禁止转载,否则通过维权骑士追究

【完整源代码请点击 此处 留言以获取,可以顺便给颗Star😄】

记录一个练习小项目,训练一下python分析技能。用到的知识有“爬虫”、“jieba分词”、“wordcloud词云”、“Tableau可视化”

准备环境

spyder

直接使用anaconda中的spyder IDE,毕竟anaconda管理各种组件、包非常方便

python

python版本为3.6.4,之前参考网上不少资料,很多代码是用python2写的,比如unicode在python3中已经没有了
但有些博文中的读取txt文件部分,仍用的python2方法,且不注明环境。千古文章一大抄

jieba

jieba库没有被anaconda收录,所以需要自己去下载安装,是zip格式
直接解压到D:\Anaconda\pkgs 目录下,打开 Anaconda Prompt并cd进入jieba解压目录,执行python setup.py install

wordcloud

这个地方遇到不少问题,因为我没安装vs,不具有vc编译环境,所以直接从github上下载wordcloud的压缩包执行python setup.py install直接报错了!
去网上查了下资料,发现是缺少一个vc-build-tool下载安装需要4G左右(ps:坑爹啊)
后来在wordcloud的github主页上找到了安装whl文件(已经被编译过)的替代方法

whl

whl格式本质上是一个压缩包,里面包含了py文件,以及经过编译的pyd文件。使得可以在不具备编译环境的情况下,选择合适自己的python环境进行安装。
安装方法很简单,进入命令行输入
pip install xxxx.whl
或者如果是升级
pip install -U xxxx.whl

流程概述

  • 爬取歌词,保存为txt文件
  • bat命令,合并同一个歌手所有txt文件(建立一个bat文件,内容为 type *.txt >> all.txt,编码和源文件相同)
  • 对合并的歌词txt文件,调用jieba进行分词
  • 针对分词的结果绘制词云图
  • 统计分词结果,Tableau进行结果展示分析

爬取歌词

在download_lyric(1007170)这句中改歌手ID1007170即可爬取其他歌手的全部歌曲歌词
歌词源来自网易云音乐;从歌手主页上爬取网易收录的该歌手所有歌曲




def get_html(url):
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36'}
    try:
        response = requests.get(url, headers=headers)
        html = response.content
        return html
    except:
        print('request error')
        pass

def download_by_music_id(music_id):
    lrc_url = 'http://music.163.com/api/song/lyric?'+'id='+str(music_id) + '&lv=1&kv=1&tv=-1'
    r = requests.get(lrc_url)
    json_obj = r.text
    j = json.loads(json_obj)
    try:
        lrc = j['lrc']['lyric']
        pat = re.compile(r'\[.*\]')
        lrc = re.sub(pat, "",lrc)
        lrc = lrc.strip()
        return lrc
    except:
        pass

def get_music_ids_by_musician_id(singer_id):
    singer_url = 'http://music.163.com/artist?id={}'.format(singer_id)
    r = get_html(singer_url)
    soupObj = BeautifulSoup(r,'lxml')
    song_ids = soupObj.find('textarea').text
    jobj = json.loads(song_ids)
    ids = {}
    for item in jobj:
        print(item['id'])
        ids[item['name']] = item['id']
    return ids

def download_lyric(uid):
    try:
        os.mkdir(str(uid))
    except:
        pass

    os.chdir(str(uid))
    music_ids = get_music_ids_by_musician_id(uid)
    for key in music_ids:
        text = download_by_music_id(music_ids[key])        
        file = open(key+'.txt', 'a', encoding='ansi')  #创建的文本以ansi编码
        file.write(key+'\n')
        file.write(str(text))
        file.close()

if __name__ == '__main__':
    download_lyric(1007170)     #只需要在这里更改网易云音乐web网站上,歌手主页url后的ID即可,比如陈粒是1007170

jieba分词

参考

添加自定义词典(usr_dict)

  • 开发者可以指定自己自定义的词典,以便包含 jieba 词库里没有的词。虽然 jieba 有新词识别能力,但是自行添加新词可以保证更高的正确率
  • 用法: jieba.load_userdict(file_name) # file_name 为文件类对象或自定义词典的路径
  • 词典格式和 dict.txt 一样,一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。file_name 若为路径或二进制方式打开的文件,则文件必须为 UTF-8 编码。
  • 词频省略时使用自动计算的能保证分出该词的词频。

添加忽略词语(stop_word)

  • 主要思想是分词过后,遍历一下停用词表,去掉停用词。
#!/usr/bin/env python3
#遇到的编码字符流问题参考了如下博客的解决方案
#https://blog.csdn.net/zhangyunfei_happy/article/details/47169939
jieba.load_userdict('usr_dict.txt')
def stopwordslist(filepath):
    stopwords = [line.strip() for line in open(filepath, 'r',encoding='utf-8').readlines()]
    return stopwords

# 对句子进行分词
def seg_sentence(sentence):
    sentence_seged = jieba.cut(sentence.strip())
    stopwords = stopwordslist('stop_word.txt')  # 这里加载停用词的路径
    outstr = ''
    for word in sentence_seged:
        if word not in stopwords:
            if word != '\t':
                outstr += word
                outstr += " "
    return outstr

if __name__ == '__main__':
    
   
    inputs = open('all.txt', 'r',encoding='ansi')  #源文件是'utf-8'编码,
    outputs = open('all_outputs.txt', 'w',encoding='utf-8')  #保存为utf8编码
    for line in inputs:
        line_seg = seg_sentence(line)  # 这里的返回值是字符串
        #注意有些符号是中英文两种格式,所以都要包含进去
        line_seg = re.sub("[A-Za-z0-9\[\`\~\!\@\#\$\^\&\*\(\)\=\|\{\}\'\:\;\'\,\[\]\.\<\>\/\?\~\!\@\#\\\&\*\%\:\(\)]", "", line_seg)
        outputs.write(line_seg)
        outputs.write('\n')
    outputs.close()
    inputs.close()

wordcloud词云

选择背景图片,颜色最好对比分明,不然生成的词图,轮廓不明显

# coding: utf-8
import re
import jieba
from scipy.misc import imread  # 这是一个处理图像的函数
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator

import matplotlib.pyplot as plt
#选择背景图片,颜色最好对比分明,不然生成的词图,轮廓不明显
back_color = imread('chenli.jpg')  # 解析该图片

# WordCloud各含义参数请点击 wordcloud参数
wc = WordCloud(background_color='white',  # 背景颜色
               max_words=1000,  # 最大词数
               mask=back_color,  # 以该参数值作图绘制词云,这个参数不为空时,width和height会被忽略
               max_font_size=100,  # 显示字体的最大值
               stopwords=STOPWORDS.add(' '),  # 使用内置的屏蔽词,再添加'苟利国'
               font_path="C:/Windows/Fonts/msyhbd.ttc",  # 显示中文,从属性里复制字体名称,不能直接看windows显示的字体名
               random_state=42,  # 为每个词返回一个PIL颜色
               # width=1000,  # 图片的宽
               # height=860  #图片的长
               )


# 添加自己的词库分词,比如添加'陈粒啊'到jieba词库后,当你处理的文本中含有“陈粒啊”这个词,
# 就会直接将'陈粒啊'当作一个词,而不会得到'陈粒'或'粒啊'这样的词
jieba.add_word('陈粒啊')

# 打开词源的文本文件,加read以字符串的形式
txt = open('all_outputs.txt','r',encoding='UTF-8').read()
# 去除文本中的英文,特殊符号等,只保留中文
txt = re.sub("[A-Za-z0-9\[\`\~\!\@\#\$\^\&\*\(\)\=\|\{\}\'\:\;\'\,\[\]\.\<\>\/\?\~\!\@\#\\\&\*\%]", "", txt)

# 该函数的作用就是把屏蔽词去掉,使用这个函数就不用在WordCloud参数中添加stopwords参数了
# 把你需要屏蔽的词全部放入一个stopwords文本文件里即可
def stop_words(texts):
    words_list = []
    word_generator = jieba.cut(texts, cut_all=False)  # 返回的是一个迭代器
    with open('stop_word.txt','r',encoding='UTF-8') as f:
        str_text = f.read()
        #print(str_text)  #如果不知道解码是否正确,可print一下,看输出的中文是否乱码
        f.close()  # stopwords文本中词的格式是'一词一行'
    for word in word_generator:
        if word.strip() not in str_text:
            words_list.append(word)
    return ' '.join(words_list)  # 注意是空格

# 分词统计
把分词后的结果按`词语+频数`的格式保存为txt和excel文件,方便Tableau处理加工
``` python
# -*- coding:utf-8 -*-
import sys, jieba, jieba.analyse, xlwt
if __name__ == "__main__":
    wbk = xlwt.Workbook(encoding='ascii')
    sheet = wbk.add_sheet("wordCount")  # Excel单元格名字
    word_lst = []
    key_list = []
    for line in open('all_outputs.txt', 'rb'):  # 1.txt是需要分词统计的文档
        item = line.strip('\n\r'.encode('utf-8')).split('\t'.encode('utf-8'))  # 制表格切分
       
        tags = jieba.analyse.extract_tags(item[0])  # jieba分词
        for t in tags:
            word_lst.append(t)
    word_dict = {}
    with open("wordCount.txt", 'bw') as wf2:  # 打开文件
        for item in word_lst:
            if item not in word_dict:  # 统计数量
                word_dict[item] = 1
            else:
                word_dict[item] += 1
        orderList = list(word_dict.values())
        orderList.sort(reverse=True)
        # print orderList
        for i in range(len(orderList)):
            for key in word_dict:
                if word_dict[key] == orderList[i]:
                    wf2.write((key + ' ' + str(word_dict[key])).encode('utf-8'))  # 写入txt文档
                    wf2.write('\n'.encode('utf-8'))  # 写入txt文档
                    key_list.append(key)
                    word_dict[key] = 0

    for i in range(len(key_list)): #为了便于tableau限量统计,可改为 for i in range(200),限定200个词
        sheet.write(i, 1, label=orderList[i])
        sheet.write(i, 0, label=key_list[i])
    wbk.save('wordCount.xls')  # 保存为 wordCount.xls文件

结果展示

获取的歌词文件

进行分词

分词统计

词云

陈粒.png

陈粒的词云


赵雷.png

赵雷的词云

Tableau可视化

赵雷统计.png

赵雷的歌词频数统计


陈粒统计.png

陈粒的歌词频数统计


对比.png

陈、赵歌词相似度统计

遇到的问题

wordcloud命名问题

File "E:\CZK\工作\数据分析\我的练习项目\词云项目\wordcloud.py", line 5, in <module>
    from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
ImportError: cannot import name 'WordCloud'

解决办法

从wordcloud作者的github及stackoverflow上均找到了答案,不得不说google搜索大法好!
改py文件的名字,就是不要以“wordcloud”命名你的py文件

包未编译问题

  File "E:/CZK/工作/数据分析/我的练习项目/词云项目/get_wordcloud.py", line 4, in <module>
    from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
ModuleNotFoundError: No module named 'wordcloud'

解决办法

下载whl文件,http://www.lfd.uci.edu/~gohlke/pythonlibs/#wordcloud
然后 pip install <whl文件名>

编码和读取文件

AttributeError: '_io.TextIOWrapper' object has no attribute 'decode' 

解决办法

jieba.cut第一个参数为str不是file,所以open文件时需要有.read()
另外读取,存储文本时,要注意源文件编码,encoding=xxxx,具体可阅读源代码

推荐阅读更多精彩内容

  • jieba分词,学习,为了全面了解该模块,,预设学习路线:官方文档——优秀博客文章——实践学习 官方文档部分 (文...
    竹林徒儿阅读 2,047评论 1 11
  • 作者:黎智煊 叩丁狼高级讲师。原创文章,转载请注明出处。 前言:现在制作一个词云图还是简单的事,例如这个-> h...
    叩丁狼教育阅读 9,749评论 1 3
  • 目录 方法概述 分词——Jieba 词频分析与词云 方法概述 1、使用歌曲《山僧》的歌词片段为素材,进行分析。 经...
    Hana_5f9b阅读 304评论 0 1
  • 关于词云wordcloud 什么是词云呢?词云又叫文字云,是对文本数据中出现频率较高的“关键词”在视觉上的突出呈现...
    abel_cao阅读 2,132评论 3 51
  • 每天晚上睡觉之前,我都会拿着kindle看一小会书。像民国的老毒棍抽大烟一样,斜躺着身体靠在床上吸食精神鸦片...
    melongod1阅读 11,313评论 7 32