未经同意禁止转载,否则通过维权骑士追究
【完整源代码请点击 此处 留言以获取,可以顺便给颗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文件
结果展示
获取的歌词文件
进行分词
分词统计
词云
陈粒的词云
赵雷的词云
Tableau可视化
赵雷的歌词频数统计
陈粒的歌词频数统计
陈、赵歌词相似度统计
遇到的问题
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,具体可阅读源代码