未經(jīng)同意禁止轉(zhuǎn)載,否則通過(guò)維權(quán)騎士追究
【完整源代碼請(qǐng)點(diǎn)擊 此處 留言以獲取,可以順便給顆Star??】
記錄一個(gè)練習(xí)小項(xiàng)目,訓(xùn)練一下python分析技能。用到的知識(shí)有“爬蟲(chóng)”、“jieba分詞”、“wordcloud詞云”、“Tableau可視化”
準(zhǔn)備環(huán)境
spyder
直接使用anaconda中的spyder IDE,畢竟anaconda管理各種組件、包非常方便
python
python版本為3.6.4,之前參考網(wǎng)上不少資料,很多代碼是用python2寫的,比如unicode在python3中已經(jīng)沒(méi)有了
但有些博文中的讀取txt文件部分,仍用的python2方法,且不注明環(huán)境。千古文章一大抄
jieba
jieba庫(kù)沒(méi)有被anaconda收錄,所以需要自己去下載安裝,是zip格式
直接解壓到D:\Anaconda\pkgs 目錄下,打開(kāi) Anaconda Prompt并cd進(jìn)入jieba解壓目錄,執(zhí)行python setup.py install
wordcloud
這個(gè)地方遇到不少問(wèn)題,因?yàn)槲覜](méi)安裝vs,不具有vc編譯環(huán)境,所以直接從github上下載wordcloud的壓縮包執(zhí)行python setup.py install直接報(bào)錯(cuò)了!
去網(wǎng)上查了下資料,發(fā)現(xiàn)是缺少一個(gè)vc-build-tool下載安裝需要4G左右(ps:坑爹?。?br>
后來(lái)在wordcloud的github主頁(yè)上找到了安裝whl文件(已經(jīng)被編譯過(guò))的替代方法
whl
whl格式本質(zhì)上是一個(gè)壓縮包,里面包含了py文件,以及經(jīng)過(guò)編譯的pyd文件。使得可以在不具備編譯環(huán)境的情況下,選擇合適自己的python環(huán)境進(jìn)行安裝。
安裝方法很簡(jiǎn)單,進(jìn)入命令行輸入
pip install xxxx.whl
或者如果是升級(jí)
pip install -U xxxx.whl
流程概述
- 爬取歌詞,保存為txt文件
- bat命令,合并同一個(gè)歌手所有txt文件(建立一個(gè)bat文件,內(nèi)容為
type *.txt >> all.txt,編碼和源文件相同) - 對(duì)合并的歌詞txt文件,調(diào)用jieba進(jìn)行分詞
- 針對(duì)分詞的結(jié)果繪制詞云圖
- 統(tǒng)計(jì)分詞結(jié)果,Tableau進(jìn)行結(jié)果展示分析
爬取歌詞
在download_lyric(1007170)這句中改歌手ID1007170即可爬取其他歌手的全部歌曲歌詞
歌詞源來(lái)自網(wǎng)易云音樂(lè);從歌手主頁(yè)上爬取網(wǎng)易收錄的該歌手所有歌曲
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') #創(chuàng)建的文本以ansi編碼
file.write(key+'\n')
file.write(str(text))
file.close()
if __name__ == '__main__':
download_lyric(1007170) #只需要在這里更改網(wǎng)易云音樂(lè)web網(wǎng)站上,歌手主頁(yè)url后的ID即可,比如陳粒是1007170
jieba分詞
添加自定義詞典(usr_dict)
- 開(kāi)發(fā)者可以指定自己自定義的詞典,以便包含 jieba 詞庫(kù)里沒(méi)有的詞。雖然 jieba 有新詞識(shí)別能力,但是自行添加新詞可以保證更高的正確率
- 用法: jieba.load_userdict(file_name) # file_name 為文件類對(duì)象或自定義詞典的路徑
- 詞典格式和 dict.txt 一樣,一個(gè)詞占一行;每一行分三部分:詞語(yǔ)、詞頻(可省略)、詞性(可省略),用空格隔開(kāi),順序不可顛倒。file_name 若為路徑或二進(jìn)制方式打開(kāi)的文件,則文件必須為 UTF-8 編碼。
- 詞頻省略時(shí)使用自動(dòng)計(jì)算的能保證分出該詞的詞頻。
添加忽略詞語(yǔ)(stop_word)
- 主要思想是分詞過(guò)后,遍歷一下停用詞表,去掉停用詞。
#!/usr/bin/env python3
#遇到的編碼字符流問(wèn)題參考了如下博客的解決方案
#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
# 對(duì)句子進(jìn)行分詞
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) # 這里的返回值是字符串
#注意有些符號(hào)是中英文兩種格式,所以都要包含進(jìn)去
line_seg = re.sub("[A-Za-z0-9\[\`\~\!\@\#\$\^\&\*\(\)\=\|\{\}\'\:\;\'\,\[\]\.\<\>\/\?\~\!\@\#\\\&\*\%\:\(\)]", "", line_seg)
outputs.write(line_seg)
outputs.write('\n')
outputs.close()
inputs.close()
wordcloud詞云
選擇背景圖片,顏色最好對(duì)比分明,不然生成的詞圖,輪廓不明顯
# coding: utf-8
import re
import jieba
from scipy.misc import imread # 這是一個(gè)處理圖像的函數(shù)
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
import matplotlib.pyplot as plt
#選擇背景圖片,顏色最好對(duì)比分明,不然生成的詞圖,輪廓不明顯
back_color = imread('chenli.jpg') # 解析該圖片
# WordCloud各含義參數(shù)請(qǐng)點(diǎn)擊 wordcloud參數(shù)
wc = WordCloud(background_color='white', # 背景顏色
max_words=1000, # 最大詞數(shù)
mask=back_color, # 以該參數(shù)值作圖繪制詞云,這個(gè)參數(shù)不為空時(shí),width和height會(huì)被忽略
max_font_size=100, # 顯示字體的最大值
stopwords=STOPWORDS.add(' '), # 使用內(nèi)置的屏蔽詞,再添加'茍利國(guó)'
font_path="C:/Windows/Fonts/msyhbd.ttc", # 顯示中文,從屬性里復(fù)制字體名稱,不能直接看windows顯示的字體名
random_state=42, # 為每個(gè)詞返回一個(gè)PIL顏色
# width=1000, # 圖片的寬
# height=860 #圖片的長(zhǎng)
)
# 添加自己的詞庫(kù)分詞,比如添加'陳粒啊'到j(luò)ieba詞庫(kù)后,當(dāng)你處理的文本中含有“陳粒啊”這個(gè)詞,
# 就會(huì)直接將'陳粒啊'當(dāng)作一個(gè)詞,而不會(huì)得到'陳粒'或'粒啊'這樣的詞
jieba.add_word('陳粒啊')
# 打開(kāi)詞源的文本文件,加read以字符串的形式
txt = open('all_outputs.txt','r',encoding='UTF-8').read()
# 去除文本中的英文,特殊符號(hào)等,只保留中文
txt = re.sub("[A-Za-z0-9\[\`\~\!\@\#\$\^\&\*\(\)\=\|\{\}\'\:\;\'\,\[\]\.\<\>\/\?\~\!\@\#\\\&\*\%]", "", txt)
# 該函數(shù)的作用就是把屏蔽詞去掉,使用這個(gè)函數(shù)就不用在WordCloud參數(shù)中添加stopwords參數(shù)了
# 把你需要屏蔽的詞全部放入一個(gè)stopwords文本文件里即可
def stop_words(texts):
words_list = []
word_generator = jieba.cut(texts, cut_all=False) # 返回的是一個(gè)迭代器
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) # 注意是空格
# 分詞統(tǒng)計(jì)
把分詞后的結(jié)果按`詞語(yǔ)+頻數(shù)`的格式保存為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是需要分詞統(tǒng)計(jì)的文檔
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: # 打開(kāi)文件
for item in word_lst:
if item not in word_dict: # 統(tǒng)計(jì)數(shù)量
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限量統(tǒng)計(jì),可改為 for i in range(200),限定200個(gè)詞
sheet.write(i, 1, label=orderList[i])
sheet.write(i, 0, label=key_list[i])
wbk.save('wordCount.xls') # 保存為 wordCount.xls文件
結(jié)果展示
獲取的歌詞文件
進(jìn)行分詞
分詞統(tǒng)計(jì)
詞云

陳粒的詞云

趙雷的詞云
Tableau可視化

趙雷的歌詞頻數(shù)統(tǒng)計(jì)

陳粒的歌詞頻數(shù)統(tǒng)計(jì)

陳、趙歌詞相似度統(tǒng)計(jì)
遇到的問(wèn)題
wordcloud命名問(wèn)題
File "E:\CZK\工作\數(shù)據(jù)分析\我的練習(xí)項(xiàng)目\詞云項(xiàng)目\wordcloud.py", line 5, in <module>
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
ImportError: cannot import name 'WordCloud'
解決辦法
從wordcloud作者的github及stackoverflow上均找到了答案,不得不說(shuō)google搜索大法好!
改py文件的名字,就是不要以“wordcloud”命名你的py文件
包未編譯問(wèn)題
File "E:/CZK/工作/數(shù)據(jù)分析/我的練習(xí)項(xiàng)目/詞云項(xiàng)目/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第一個(gè)參數(shù)為str不是file,所以open文件時(shí)需要有.read()
另外讀取,存儲(chǔ)文本時(shí),要注意源文件編碼,encoding=xxxx,具體可閱讀源代碼