日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

新冠疫情微博話題抓取,文本挖掘和情感分析

 板橋胡同37號(hào) 2020-04-21

新冠肺炎終于在舉國上下的努力下得以控制,大家的工作生活也慢慢開始走向正規(guī),疫情帶來巨大的災(zāi)難,但同時(shí)也給研究者留下許多珍貴的數(shù)據(jù)。針對(duì)這次肺炎疫情,本文作者將抓取疫情相關(guān)微博話題及評(píng)論信息,采用SnowNLP進(jìn)行簡(jiǎn)單的情感分析及文本挖掘,包括隨時(shí)間的情感分布,希望對(duì)這一領(lǐng)域的學(xué)習(xí)者有幫助。

首先放上代碼下載地址:https://github.com/eastmountyxz/Wuhan-data-analysis

CSDN下載地址:

https://download.csdn.net/download/Eastmount/12239638

微博話題數(shù)據(jù)抓取

該部分內(nèi)容參考及修改我的學(xué)生兼朋友“楊友”的文章,也推薦博友們閱讀他的博客,給予支持。作為老師,最開心的事就是看到學(xué)生成長(zhǎng)和收獲。他的博客地址:python爬蟲爬取微博之戰(zhàn)疫情用戶評(píng)論及詳情

微博網(wǎng)址:https://m.weibo.cn/

1.爬蟲解析

第一步,進(jìn)入微博審查元素,定位評(píng)論對(duì)應(yīng)節(jié)點(diǎn),后續(xù)抓取評(píng)論信息。

進(jìn)入微博后,點(diǎn)擊《戰(zhàn)疫情》主題下,并隨便選擇一個(gè)動(dòng)態(tài)進(jìn)行分析,我就選擇了“央視新聞網(wǎng)”的一條動(dòng)態(tài)態(tài)“https://m.weibo.cn/detail/4471652190688865”進(jìn)行分析。

我們剛打開該話題的時(shí)候,它顯示的是187條評(píng)論,但是在審查時(shí)可以看到文章中的20個(gè)div,并且每個(gè)div中裝載一條評(píng)論,每個(gè)頁面原始就只能顯示20條評(píng)論。

當(dāng)我們把鼠標(biāo)不斷向下滑動(dòng)的過程中,網(wǎng)頁元素中的div也不斷隨評(píng)論的增加而增加,當(dāng)活動(dòng)到底部時(shí),所有評(píng)論都加載出來了。初步判斷該網(wǎng)頁屬于ajax加載類型,所以先就不要考慮用requests請(qǐng)求服務(wù)器了。

第二步,獲取Ajax加載的動(dòng)態(tài)鏈接數(shù)據(jù),通過發(fā)布id定位每條話題。

這些數(shù)據(jù)都是通過Ajax動(dòng)態(tài)加載的,點(diǎn)擊到《戰(zhàn)疫情》主題,發(fā)現(xiàn)它的URL并沒有變化,具體瀏覽幾篇文章后發(fā)現(xiàn),它的的部分URL都是統(tǒng)一的,文章鏈接 = ‘https://m.weibo.cn/detail/’+發(fā)布時(shí)的id,可以通過剛找到的 id 在瀏覽器中拼接試試。

比如下圖所示的微博內(nèi)容。比如:https://m.weibo.cn/detail/4472846740547511

第三步,下拉網(wǎng)頁動(dòng)態(tài)刷新數(shù)據(jù),發(fā)現(xiàn)獲取多個(gè)page的規(guī)律。

接下來是獲取它下一個(gè)加載數(shù)據(jù)的通道,同樣是通過抓包的方式獲取,不斷的下拉網(wǎng)頁,加載出其他的Ajax數(shù)據(jù)傳輸通道,再進(jìn)行對(duì)比??梢院苊黠@的看出,它的當(dāng)前鏈接就只是帶上了 “&page=當(dāng)前數(shù)字” 的標(biāo)簽,并且每次加載出18篇?jiǎng)討B(tài)文章。

查看元素信息如下圖所示,每個(gè)page顯示18個(gè)微博話題。

第四步,調(diào)用json.loads()函數(shù)或在線網(wǎng)站解析Json數(shù)據(jù)。

拿到的數(shù)據(jù)是json格式,再提取信息前需要把str文本轉(zhuǎn)化為json數(shù)據(jù),進(jìn)行查找,可以使用json庫查看它的結(jié)構(gòu) ,也可以在線json解析查看它的結(jié)構(gòu),更推薦在線解析,方法結(jié)構(gòu)比較清晰。

在線解析后的結(jié)果,簡(jiǎn)單的給它打上標(biāo)簽,每一個(gè)等級(jí)為一塊,一級(jí)包括二級(jí)和三級(jí),二級(jí)包括三級(jí)… 然后通過前面的標(biāo)簽進(jìn)行迭代輸出,索引出來。在線網(wǎng)站:https://www./

第五步,獲取每條微博的ID值。

調(diào)用方法如下,然后把拿到的id加在https://m.weibo.cn/detail/ 的后面就可以訪問具體的文章了。







import requestsapi_url = 'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_600059_-_ctg1_600059'reponse = requests.get(api_url)for json in reponse.json()['data']['statuses']: comment_ID = json['id'] print (comment_ID)

此時(shí)提取所有鏈接代碼如下:























import requests,time
from fake_useragent import UserAgent

comment_urls = []def get_title_id(): '''爬取戰(zhàn)疫情首頁的每個(gè)主題的ID''' for page in range(1,3):# 這是控制ajax通道的量 headers = { 'User-Agent' : UserAgent().chrome #chrome瀏覽器隨機(jī)代理 } time.sleep(2) # 該鏈接通過抓包獲得 api_url = 'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_600059_-_ctg1_600059&page=' + str(page) print (api_url) rep = requests.get(url=api_url, headers=headers) for json in rep.json()['data']['statuses']: comment_url = 'https://m.weibo.cn/detail/' + json['id'] print (comment_url) comment_urls.append(comment_url)get_title_id()

輸出結(jié)果如下:
















https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_600059_-_ctg1_600059&page=1
https://m.weibo.cn/detail/4472725286834498https://m.weibo.cn/detail/4472896510211624https://m.weibo.cn/detail/4472846892243445https://m.weibo.cn/detail/4472901455185821https://m.weibo.cn/detail/4472856669039437https://m.weibo.cn/detail/4472897055545751https://m.weibo.cn/detail/4472891342667233https://m.weibo.cn/detail/4472879381479272https://m.weibo.cn/detail/4472889565122923https://m.weibo.cn/detail/4472884950738226https://m.weibo.cn/detail/4472883461527008https://m.weibo.cn/detail/4472904014106917......

第六步,調(diào)用requests ajax 爬取更多信息。

現(xiàn)在需要獲取更多的信息,如用戶id、性別之類的,這不是selenium可以完成的操作了,還得使用ajax的方式獲取json數(shù)據(jù),提取詳細(xì)的信息。這里有個(gè)字段是max_id, 我們需要在上一個(gè)json文件底部找到該值。

目標(biāo):話題鏈接、話題內(nèi)容、樓主ID、樓主昵稱、樓主性別、發(fā)布日期、發(fā)布時(shí)間、轉(zhuǎn)發(fā)量、評(píng)論量、點(diǎn)贊量、評(píng)論者ID、評(píng)論者昵稱、評(píng)論者性別、評(píng)論日期、評(píng)論時(shí)間、評(píng)論內(nèi)容

  • 第一個(gè)通道

  • 現(xiàn)在可以預(yù)測(cè)下一個(gè)max_id

成功地通過上一個(gè)通道拿到了下一個(gè)通道的max_id,現(xiàn)在就可以使用ajax加載數(shù)據(jù)了。

2.爬蟲完整代碼
















































































































































































































# -*- coding: utf-8 -*-import requests,random,reimport timeimport osimport csvimport sysimport jsonimport importlibfrom fake_useragent import UserAgentfrom lxml import etree

importlib.reload(sys)startTime = time.time() #記錄起始時(shí)間

#--------------------------------------------文件存儲(chǔ)-----------------------------------------------------path = os.getcwd() + '/weiboComments.csv'csvfile = open(path, 'a', newline='', encoding = 'utf-8-sig')writer = csv.writer(csvfile)#csv頭部writer.writerow(('話題鏈接','話題內(nèi)容','樓主ID', '樓主昵稱', '樓主性別','發(fā)布日期', '發(fā)布時(shí)間', '轉(zhuǎn)發(fā)量','評(píng)論量','點(diǎn)贊量', '評(píng)論者ID', '評(píng)論者昵稱', '評(píng)論者性別', '評(píng)論日期', '評(píng)論時(shí)間','評(píng)論內(nèi)容'))

#設(shè)置headesheaders = { 'Cookie': '_T_WM=22822641575; H5_wentry=H5; backURL=https%3A%2F%2Fm.weibo.cn%2F; ALF=1584226439; MLOGIN=1; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9W5RJaVYrb.BEuOvUQ8Ca2OO5JpX5K-hUgL.FoqESh-7eKzpShM2dJLoIp7LxKML1KBLBKnLxKqL1hnLBoMceoBfeh2EeKBN; SCF=AnRSOFp6QbWzfH1BqL4HB8my8eWNC5C33KhDq4Ko43RUIzs6rjJC49kIvz5_RcOJV2pVAQKvK2UbAd1Uh6j0pyo.; SUB=_2A25zQaQBDeRhGeBM71cR8SzNzzuIHXVQzcxJrDV6PUJbktAKLXD-kW1NRPYJXhsrLRnku_WvhsXi81eY0FM2oTtt; SUHB=0mxU9Kb_Ce6s6S; SSOLoginState=1581634641; WEIBOCN_FROM=1110106030; XSRF-TOKEN=dc7c27; M_WEIBOCN_PARAMS=oid%3D4471980021481431%26luicode%3D20000061%26lfid%3D4471980021481431%26uicode%3D20000061%26fid%3D4471980021481431', 'Referer': 'https://m.weibo.cn/detail/4312409864846621', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.100 Safari/537.36', 'X-Requested-With': 'XMLHttpRequest'}

#-----------------------------------爬取戰(zhàn)疫情首頁的每個(gè)主題的ID------------------------------------------comments_ID = []def get_title_id(): for page in range(1,21): #每個(gè)頁面大約有18個(gè)話題 headers = { 'User-Agent' : UserAgent().chrome #chrome瀏覽器隨機(jī)代理 } time.sleep(1) #該鏈接通過抓包獲得 api_url = 'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_600059_-_ctg1_600059&page=' + str(page) print(api_url) rep = requests.get(url=api_url, headers=headers) #獲取ID值并寫入列表comment_ID中 for json in rep.json()['data']['statuses']: comment_ID = json['id'] comments_ID.append(comment_ID)

#-----------------------------------爬取戰(zhàn)疫情每個(gè)主題的詳情頁面------------------------------------------ def spider_title(comment_ID): try: article_url = 'https://m.weibo.cn/detail/'+ comment_ID print ('article_url = ', article_url) html_text = requests.get(url=article_url, headers=headers).text #話題內(nèi)容 find_title = re.findall('.*?'text': '(.*?)',.*?', html_text)[0] title_text = re.sub('<(S*?)[^>]*>.*?|<.*? />', '', find_title) #正則匹配掉html標(biāo)簽 print ('title_text = ', title_text) #樓主ID title_user_id = re.findall('.*?'id': (.*?),.*?', html_text)[1] print ('title_user_id = ', title_user_id) #樓主昵稱 title_user_NicName = re.findall('.*?'screen_name': '(.*?)',.*?', html_text)[0] print ('title_user_NicName = ', title_user_NicName) #樓主性別 title_user_gender = re.findall('.*?'gender': '(.*?)',.*?', html_text)[0] print ('title_user_gender = ', title_user_gender) #發(fā)布時(shí)間 created_title_time = re.findall('.*?'created_at': '(.*?)'.*?', html_text)[0].split(' ') #日期 if 'Mar' in created_title_time: title_created_YMD = '{}/{}/{}'.format(created_title_time[-1], '03', created_title_time[2]) elif 'Feb' in created_title_time: title_created_YMD = '{}/{}/{}'.format(created_title_time[-1], '02', created_title_time[2]) elif 'Jan' in created_title_time: title_created_YMD = '{}/{}/{}'.format(created_title_time[-1], '01', created_title_time[2]) else: print ('該時(shí)間不在疫情范圍內(nèi),估計(jì)數(shù)據(jù)有誤!URL = ') pass print ('title_created_YMD = ', title_created_YMD) #發(fā)布時(shí)間 add_title_time = created_title_time[3] print ('add_title_time = ', add_title_time) #轉(zhuǎn)發(fā)量 reposts_count = re.findall('.*?'reposts_count': (.*?),.*?', html_text)[0] print ('reposts_count = ', reposts_count) #評(píng)論量 comments_count = re.findall('.*?'comments_count': (.*?),.*?', html_text)[0] print ('comments_count = ', comments_count) #點(diǎn)贊量 attitudes_count = re.findall('.*?'attitudes_count': (.*?),.*?', html_text)[0] print ('attitudes_count = ', attitudes_count) comment_count = int(int(comments_count) / 20) #每個(gè)ajax一次加載20條數(shù)據(jù) position1 = (article_url, title_text, title_user_id, title_user_NicName,title_user_gender, title_created_YMD, add_title_time, reposts_count, comments_count, attitudes_count, ' ', ' ', ' ', ' ',' ', ' ') #寫入數(shù)據(jù) writer.writerow((position1)) return comment_count except: pass



#-------------------------------------------------抓取評(píng)論信息---------------------------------------------------#comment_ID話題編號(hào)def get_page(comment_ID, max_id, id_type): params = { 'max_id': max_id, 'max_id_type': id_type } url = ' https://m.weibo.cn/comments/hotflow?id={}&mid={}&max_id'.format(comment_ID, comment_ID) try: r = requests.get(url, params=params, headers=headers) if r.status_code == 200: return r.json() except requests.ConnectionError as e: print('error', e.args) pass

#-------------------------------------------------抓取評(píng)論item最大值---------------------------------------------------def parse_page(jsondata): if jsondata: items = jsondata.get('data') item_max_id = {} item_max_id['max_id'] = items['max_id'] item_max_id['max_id_type'] = items['max_id_type'] return item_max_id

#-------------------------------------------------抓取評(píng)論信息---------------------------------------------------def write_csv(jsondata): for json in jsondata['data']['data']: #用戶ID user_id = json['user']['id'] # 用戶昵稱 user_name = json['user']['screen_name'] # 用戶性別,m表示男性,表示女性 user_gender = json['user']['gender'] #獲取評(píng)論 comments_text = json['text'] comment_text = re.sub('<(S*?)[^>]*>.*?|<.*? />', '', comments_text) #正則匹配掉html標(biāo)簽 # 評(píng)論時(shí)間 created_times = json['created_at'].split(' ') if 'Feb' in created_times: created_YMD = '{}/{}/{}'.format(created_times[-1], '02', created_times[2]) elif 'Jan' in created_times: created_YMD = '{}/{}/{}'.format(created_times[-1], '01', created_times[2]) else: print ('該時(shí)間不在疫情范圍內(nèi),估計(jì)數(shù)據(jù)有誤!') pass created_time = created_times[3] #評(píng)論時(shí)間時(shí)分秒 #if len(comment_text) != 0: position2 = (' ', ' ', ' ', ' ',' ', ' ', ' ', ' ', ' ', ' ', user_id, user_name, user_gender, created_YMD, created_time, comment_text) writer.writerow((position2))#寫入數(shù)據(jù) #print (user_id, user_name, user_gender, created_YMD, created_time)



#-------------------------------------------------主函數(shù)---------------------------------------------------def main(): count_title = len(comments_ID) for count, comment_ID in enumerate(comments_ID): print ('正在爬取第%s個(gè)話題,一共找到個(gè)%s話題需要爬取'%(count+1, count_title)) #maxPage獲取返回的最大評(píng)論數(shù)量 maxPage = spider_title(comment_ID) print ('maxPage = ', maxPage) m_id = 0 id_type = 0 if maxPage != 0: #小于20條評(píng)論的不需要循環(huán) try: #用評(píng)論數(shù)量控制循環(huán) for page in range(0, maxPage): #自定義函數(shù)-抓取網(wǎng)頁評(píng)論信息 jsondata = get_page(comment_ID, m_id, id_type)
#自定義函數(shù)-寫入CSV文件 write_csv(jsondata)
#自定義函數(shù)-獲取評(píng)論item最大值 results = parse_page(jsondata) time.sleep(1) m_id = results['max_id'] id_type = results['max_id_type'] except: pass print ('--------------------------分隔符---------------------------') csvfile.close()
if __name__ == '__main__':
#獲取話題ID get_title_id()
#主函數(shù)操作 main()
#計(jì)算使用時(shí)間 endTime = time.time() useTime = (endTime-startTime) / 60 print('該次所獲的信息一共使用%s分鐘'%useTime)

保存數(shù)據(jù)截圖如下圖所示:

下圖時(shí)抓取的話題頁面網(wǎng)址,每個(gè)頁面包括18個(gè)話題。

接著抓取每個(gè)話題的內(nèi)容,如下所示:



























正在爬取第1個(gè)話題,一共找到個(gè)361話題需要爬取article_url = https://m.weibo.cn/detail/4484575189181757title_text = 【#國家衛(wèi)健委回應(yīng)健康碼互通互認(rèn)#】國家衛(wèi)生健康委規(guī)劃司司長(zhǎng)毛群安:目前全國低風(fēng)險(xiǎn)縣域已占98%,各省份正在按照統(tǒng)一的數(shù)據(jù)格式標(biāo)準(zhǔn)和內(nèi)容要求,加快向全國一體化平臺(tái)匯聚本地區(qū)防疫健康信息的目錄。截至目前,#全國絕大多數(shù)健康碼可實(shí)現(xiàn)一碼通行#。微博視頻 title_user_id = 2803301701title_user_NicName = title_user_gender = m該時(shí)間不在疫情范圍內(nèi),估計(jì)數(shù)據(jù)有誤!URL = maxPage = None--------------------------分隔符---------------------------正在爬取第2個(gè)話題,一共找到個(gè)361話題需要爬取article_url = https://m.weibo.cn/detail/4484288164243251title_text = 法國網(wǎng)友自稱自己成了長(zhǎng)發(fā)公主,度過了居家隔離后的第三天.....#全球疫情##法國疫情# 法國囧事的微博視頻 title_user_id = 2981906842title_user_NicName = 法國囧事title_user_gender = m該時(shí)間不在疫情范圍內(nèi),估計(jì)數(shù)據(jù)有誤!URL = maxPage = None--------------------------分隔符---------------------------正在爬取第3個(gè)話題,一共找到個(gè)361話題需要爬取article_url = https://m.weibo.cn/detail/4484492666507389title_text = #全球疫情# #意大利疫情# #意大利# “羅馬還有其他四處的藥店都遭到了搶劫。我們?cè)馐艿降氖浅中祿尳佟!斑@是一位羅馬藥店藥劑師的陳述。她說,在當(dāng)前疫情的危機(jī)情況下,我們處在兩難困境之中:受到搶劫和疾病的雙重威脅。疫情之下,意大利口罩告急,價(jià)格飆高。市民認(rèn)為是藥店不賣,而真實(shí)情況是藥店真的沒有,而供貨商又抬高了價(jià)格。藥店處在兩難境地。這位藥劑師道出了自己的苦衷,冒著危險(xiǎn)還在工作,與醫(yī)護(hù)人員一樣,都是奮斗在一線做出犧牲的人。呼吁民眾理解,也請(qǐng)求大家的幫助。Nita大呵呵的微博視頻title_user_id = 6476189426title_user_NicName = Nita大呵呵title_user_gender = f該時(shí)間不在疫情范圍內(nèi),估計(jì)數(shù)據(jù)有誤!URL = maxPage = None

最終抓取360個(gè)疫情話題內(nèi)容。

注意:該爬蟲評(píng)論寫入功能需要改進(jìn)下,且只能抓取當(dāng)天的“戰(zhàn)疫情”話題及評(píng)論,如果想針對(duì)某個(gè)突發(fā)事件進(jìn)行一段時(shí)間的分析,建議每天定時(shí)運(yùn)行該程序,從而形成所需的數(shù)據(jù)集。也可以根據(jù)需求修改為熱點(diǎn)話題的抓取,增加搜索功能等。

微博話題詞云分析

首先,我們對(duì)文本進(jìn)行簡(jiǎn)單的詞云可視化分析。

1.基本用法

詞云分析主要包括兩種方法:

  • 調(diào)用WordCloud擴(kuò)展包畫圖(兼容性極強(qiáng),之前介紹過)

  • 調(diào)用PyEcharts中的WordCloud子包畫圖(本文推薦新方法)

PyEcharts繪制詞云的基礎(chǔ)代碼如下:













































# coding=utf-8
from pyecharts import options as optsfrom pyecharts.charts import WordCloudfrom pyecharts.globals import SymbolType

# 數(shù)據(jù)words = [ ('背包問題', 10000), ('大整數(shù)', 6181), ('Karatsuba乘法算法', 4386), ('窮舉搜索', 4055), ('傅里葉變換', 2467), ('狀態(tài)樹遍歷', 2244), ('剪枝', 1868), ('Gale-shapley', 1484), ('最大匹配與匈牙利算法', 1112), ('線索模型', 865), ('關(guān)鍵路徑算法', 847), ('最小二乘法曲線擬合', 582), ('二分逼近法', 555), ('牛頓迭代法', 550), ('Bresenham算法', 462), ('粒子群優(yōu)化', 366), ('Dijkstra', 360), ('A*算法', 282), ('負(fù)極大極搜索算法', 273), ('估值函數(shù)', 265)]

# 渲染圖def wordcloud_base() -> WordCloud: c = ( WordCloud() .add('', words, word_size_range=[20, 100], shape='diamond') # SymbolType.ROUND_RECT .set_global_opts(title_opts=opts.TitleOpts(title='WordCloud詞云')) ) return c

# 生成圖wordcloud_base().render('詞云圖.html')

輸出結(jié)果如下圖所示,出現(xiàn)詞頻越高顯示越大。

核心代碼為:


add(name, attr, value, shape=“circle”, word_gap=20, word_size_range=None, rotate_step=45)
  • name -> str: 圖例名稱

  • attr -> list: 屬性名稱

  • value -> list: 屬性所對(duì)應(yīng)的值

  • shape -> list: 詞云圖輪廓,有’circle’, ‘cardioid’, ‘diamond’, ‘triangleforward’, ‘triangle’, ‘pentagon’, ‘star’可選

  • word_gap -> int: 單詞間隔,默認(rèn)為20

  • word_size_range -> list: 單詞字體大小范圍,默認(rèn)為[12,60]

  • rotate_step -> int: 旋轉(zhuǎn)單詞角度,默認(rèn)為45

2.疫情詞云

接著我們將3月20日疫情內(nèi)容復(fù)制至“data.txt”文本,經(jīng)過中文分詞后顯示前1000個(gè)高頻詞的詞云。代碼如下:














































































# coding=utf-8import jiebaimport reimport timefrom collections import Counter

#------------------------------------中文分詞------------------------------------cut_words = ''all_words = ''f = open('C-class-fenci.txt', 'w')for line in open('C-class.txt', encoding='utf-8'): line.strip('\n') seg_list = jieba.cut(line,cut_all=False) # print(' '.join(seg_list)) cut_words = (' '.join(seg_list)) f.write(cut_words) all_words += cut_wordselse: f.close()

# 輸出結(jié)果all_words = all_words.split()print(all_words)

# 詞頻統(tǒng)計(jì)c = Counter()for x in all_words: if len(x)>1 and x != '\r\n': c[x] += 1

# 輸出詞頻最高的前10個(gè)詞print('\n詞頻統(tǒng)計(jì)結(jié)果:')for (k,v) in c.most_common(10): print('%s:%d'%(k,v))

# 存儲(chǔ)數(shù)據(jù)name = time.strftime('%Y-%m-%d') + '-fc.csv'fw = open(name, 'w', encoding='utf-8')i = 1for (k,v) in c.most_common(len(c)): fw.write(str(i)+','+str(k)+','+str(v)+'\n') i = i + 1else: print('Over write file!') fw.close()

#------------------------------------詞云分析------------------------------------from pyecharts import options as optsfrom pyecharts.charts import WordCloudfrom pyecharts.globals import SymbolType

# 生成數(shù)據(jù) word = [('A',10), ('B',9), ('C',8)] 列表+Tuplewords = []for (k,v) in c.most_common(1000): # print(k, v) words.append((k,v))

# 渲染圖def wordcloud_base() -> WordCloud: c = ( WordCloud() .add('', words, word_size_range=[20, 100], shape=SymbolType.ROUND_RECT) .set_global_opts(title_opts=opts.TitleOpts(title='全國新型冠狀病毒疫情詞云圖')) ) return c

# 生成圖wordcloud_base().render('疫情詞云圖.html')

輸出結(jié)果如下圖所示,僅3月20日的熱點(diǎn)話題內(nèi)容。

3.WordCloud

另一種方法的代碼如下:











































































# coding=utf-8import jiebaimport reimport sysimport timefrom collections import Counterimport matplotlib.pyplot as pltfrom wordcloud import WordCloud

#------------------------------------中文分詞------------------------------------cut_words = ''all_words = ''f = open('data-fenci.txt', 'w')for line in open('data.txt', encoding='utf-8'): line.strip('\n') seg_list = jieba.cut(line,cut_all=False) # print(' '.join(seg_list)) cut_words = (' '.join(seg_list)) f.write(cut_words) all_words += cut_wordselse: f.close()

# 輸出結(jié)果all_words = all_words.split()print(all_words)

# 詞頻統(tǒng)計(jì)c = Counter()for x in all_words: if len(x)>1 and x != '\r\n': c[x] += 1

# 輸出詞頻最高的前10個(gè)詞print('\n詞頻統(tǒng)計(jì)結(jié)果:')for (k,v) in c.most_common(10): print('%s:%d'%(k,v))

# 存儲(chǔ)數(shù)據(jù)name = time.strftime('%Y-%m-%d') + '-fc.csv'fw = open(name, 'w', encoding='utf-8')i = 1for (k,v) in c.most_common(len(c)): fw.write(str(i)+','+str(k)+','+str(v)+'\n') i = i + 1else: print('Over write file!') fw.close()

#------------------------------------詞云分析------------------------------------#打開本體TXT文件text = open('data.txt').read()
#結(jié)巴分詞 cut_all=True 設(shè)置為精準(zhǔn)模式 wordlist = jieba.cut(text, cut_all = False)
#使用空格連接 進(jìn)行中文分詞wl_space_split = ' '.join(wordlist)#print(wl_space_split)
#對(duì)分詞后的文本生成詞云my_wordcloud = WordCloud().generate(wl_space_split)
#顯示詞云圖plt.imshow(my_wordcloud)#是否顯示x軸、y軸下標(biāo)plt.axis('off')plt.show()

SnowNLP情感分析用法

情感分析的基本流程如下圖所示,通常包括:

  • 自定義爬蟲抓取文本信息;

  • 使用Jieba工具進(jìn)行中文分詞、詞性標(biāo)注;

  • 定義情感詞典提取每行文本的情感詞;

  • 通過情感詞構(gòu)建情感矩陣,并計(jì)算情感分?jǐn)?shù);

  • 結(jié)果評(píng)估,包括將情感分?jǐn)?shù)置于0.5到-0.5之間,并可視化顯示。

1.SnowNLP

SnowNLP是一個(gè)常用的Python文本分析庫,是受到TextBlob啟發(fā)而發(fā)明的。由于當(dāng)前自然語言處理庫基本都是針對(duì)英文的,而中文沒有空格分割特征詞,Python做中文文本挖掘較難,后續(xù)開發(fā)了一些針對(duì)中文處理的庫,例如SnowNLP、Jieba、BosonNLP等。注意SnowNLP處理的是unicode編碼,所以使用時(shí)請(qǐng)自行decode成unicode。

Snownlp主要功能包括:

  • 中文分詞(算法是Character-Based Generative Model)

  • 詞性標(biāo)注(原理是TnT、3-gram 隱馬)

  • 情感分析

  • 文本分類(原理是樸素貝葉斯)

  • 轉(zhuǎn)換拼音、繁體轉(zhuǎn)簡(jiǎn)體

  • 提取文本關(guān)鍵詞(原理是TextRank)

  • 提取摘要(原理是TextRank)、分割句子

  • 文本相似(原理是BM25)

推薦官網(wǎng)給大家學(xué)習(xí)。

安裝和其他庫一樣,使用pip安裝即可。


pip install snownlp

2.中文分詞

下面是最簡(jiǎn)單的實(shí)例,使用SnowNLP進(jìn)行中文分詞,同時(shí)比較了SnowNLP和Jieba庫的分詞效果。












# -*- coding: utf-8 -*-from snownlp import SnowNLPs1 = SnowNLP(u'這本書質(zhì)量真不太好!')print('SnowNLP:')print(' '.join(s1.words))

import jiebas2 = jieba.cut(u'這本書質(zhì)量真不太好!', cut_all=False)print('jieba:')print(' '.join(s2))

輸出結(jié)果如下所示:

總體感覺是SnowNLP分詞速度比較慢,準(zhǔn)確度較低,比如“不太好”這個(gè)詞組,但也不影響我們后續(xù)的情感分析。

3.常見功能

代碼如下:












































# -*- coding: utf-8 -*-from snownlp import SnowNLPs = SnowNLP(u'這本書質(zhì)量真不太好!')

print(u'\n中文分詞:')print( ' '.join(s.words))

print(u'\n詞性標(biāo)注:')print(s.tags)for k in s.tags: print(k)

print(u'\n情感分?jǐn)?shù):')print(s.sentiments)

print(u'\n轉(zhuǎn)換拼音:')print(s.pinyin)

print(u'\n輸出前4個(gè)關(guān)鍵詞:')print(s.keywords(4))for k in s.keywords(4): print(k)

print(u'\n輸出關(guān)鍵句子:')print(s.summary(1))for k in s.summary(1): print(k)

print(u'\n輸出tf和idf:')print(s.tf)print(s.idf)

n = SnowNLP(u'「繁體字」「繁體中文」的叫法在臺(tái)灣亦很常見。')print(u'\n繁簡(jiǎn)體轉(zhuǎn)換:')print(n.han)

s.words 輸出分詞后的結(jié)果,詞性標(biāo)注主要通過 s.tags,s.sentiments 計(jì)算情感分?jǐn)?shù),s.pinyin 轉(zhuǎn)換為拼音,s.keywords(4) 提取4個(gè)關(guān)鍵詞,s.summary(1) 輸出一個(gè)關(guān)鍵句子,s.tf 計(jì)算TF值(頻率),s.idf 計(jì)算IDF值(倒文檔)。

輸出結(jié)果如下所示:























































>>>

中文分詞:這 本書 質(zhì)量 真 不 太 好 !

詞性標(biāo)注:[(u'\u8fd9', u'r'), (u'\u672c\u4e66', u'r'), (u'\u8d28\u91cf', u'n'), (u'\u771f', u'd'), (u'\u4e0d', u'd'), (u'\u592a', u'd'), (u'\u597d', u'a'), (u'\uff01', u'w')](u'\u8fd9', u'r')(u'\u672c\u4e66', u'r')(u'\u8d28\u91cf', u'n')(u'\u771f', u'd')(u'\u4e0d', u'd')(u'\u592a', u'd')(u'\u597d', u'a')(u'\uff01', u'w')

情感分?jǐn)?shù):0.420002029202

轉(zhuǎn)換拼音:[u'zhe', u'ben', u'shu', u'zhi', u'liang', u'zhen', u'bu', u'tai', u'hao', u'\uff01']

輸出前4個(gè)關(guān)鍵詞:[u'\u592a', u'\u4e0d', u'\u8d28\u91cf', u'\u771f']質(zhì)量

輸出關(guān)鍵句子:[u'\u8fd9\u672c\u4e66\u8d28\u91cf\u771f\u4e0d\u592a\u597d']這本書質(zhì)量真不太好

輸出tf和idf:[{u'\u8fd9': 1}, {u'\u672c': 1}, {u'\u4e66': 1}, {u'\u8d28': 1}, {u'\u91cf': 1}, {u'\u771f': 1}, {u'\u4e0d': 1}, {u'\u592a': 1}, {u'\u597d': 1}, {u'\uff01': 1}]{u'\uff01': 1.845826690498331, u'\u4e66': 1.845826690498331, u'\u8d28': 1.845826690498331, u'\u592a': 1.845826690498331, u'\u4e0d': 1.845826690498331, u'\u672c': 1.845826690498331, u'\u91cf': 1.845826690498331, u'\u8fd9': 1.845826690498331, u'\u597d': 1.845826690498331, u'\u771f': 1.845826690498331}

繁簡(jiǎn)體轉(zhuǎn)換:「繁體字」「繁體中文」的叫法在臺(tái)灣亦很常見。>>>

同樣可以進(jìn)行文本相似度計(jì)算,代碼參考下圖所示:

4.情感分析

SnowNLP情感分析也是基于情感詞典實(shí)現(xiàn)的,其簡(jiǎn)單的將文本分為兩類,積極和消極,返回值為情緒的概率,越接近1為積極,接近0為消極。

下面簡(jiǎn)單給出一個(gè)情感分析的例子:
















# -*- coding: utf-8 -*-from snownlp import SnowNLPs1 = SnowNLP(u'我今天很開心')print(u's1情感分?jǐn)?shù):')print(s1.sentiments)

s2 = SnowNLP(u'我今天很沮喪')print(u's2情感分?jǐn)?shù):')print(s2.sentiments)

s3 = SnowNLP(u'大傻瓜,你脾氣真差,動(dòng)不動(dòng)就打人')print(u's3情感分?jǐn)?shù):')print(s3.sentiments)

輸出結(jié)果如下所示,當(dāng)負(fù)面情感特征詞越多,比如“傻瓜”、“差”、“打人”等,分?jǐn)?shù)就會(huì)很低,同樣當(dāng)正免情感詞多分?jǐn)?shù)就高。








s1情感分?jǐn)?shù):
0.84204018979s2情感分?jǐn)?shù):0.648537121839s3情感分?jǐn)?shù):0.0533215596706

而在真實(shí)項(xiàng)目中,通常需要根據(jù)實(shí)際的數(shù)據(jù)重新訓(xùn)練情感分析的模型,導(dǎo)入正面樣本和負(fù)面樣本,再訓(xùn)練新模型。

  • sentiment.train(’./neg.txt’, ‘./pos.txt’)

  • sentiment.save(‘sentiment.marshal’)

SnowNLP微博情感分析實(shí)例

下面的代碼是對(duì)爬取的疫情話題進(jìn)行情感分析。本文將抓取的356條(其中4條僅圖片)微博疫情話題信息復(fù)制至TXT文件中 ,每一行為一條話題,再對(duì)其進(jìn)行中文分詞處理。注意,這里僅僅獲取序號(hào)1-356的情感分?jǐn)?shù),而其他情感分析可以進(jìn)行時(shí)間對(duì)比、主題對(duì)比等,其方法和此篇文章類似,希望讀者學(xué)會(huì)舉一反三。

1.情感各分?jǐn)?shù)段出現(xiàn)頻率

首先統(tǒng)計(jì)各情感分?jǐn)?shù)段出現(xiàn)的評(píng)率并繪制對(duì)應(yīng)的柱狀圖,代碼如下:























# -*- coding: utf-8 -*-from snownlp import SnowNLPimport codecsimport os

source = open('data.txt','r', encoding='utf-8')line = source.readlines()sentimentslist = []for i in line: s = SnowNLP(i) print(s.sentiments) sentimentslist.append(s.sentiments)

import matplotlib.pyplot as pltimport numpy as npplt.hist(sentimentslist, bins = np.arange(0, 1, 0.01), facecolor = 'g')plt.xlabel('Sentiments Probability')plt.ylabel('Quantity')plt.title('Analysis of Sentiments')plt.show()

輸出結(jié)果如下圖所示,可以看到

對(duì)應(yīng)的分?jǐn)?shù)如下:












>>>4.440892098500626e-160.490553956075208240.99999999999726350.99999986770931490.99796275863685160.99999999909595090.99998301992337690.99986993108126470.9999954477924106...

2.情感波動(dòng)分析

接下來分析每條評(píng)論的波動(dòng)情況,代碼如下所示:























# -*- coding: utf-8 -*-from snownlp import SnowNLPimport codecsimport os

source = open('data.txt','r', encoding='utf-8')line = source.readlines()sentimentslist = []for i in line: s = SnowNLP(i) print(s.sentiments) sentimentslist.append(s.sentiments)

import matplotlib.pyplot as pltimport numpy as npplt.plot(np.arange(0, 356, 1), sentimentslist, 'k-')plt.xlabel('Number')plt.ylabel('Sentiment')plt.title('Analysis of Sentiments')plt.show()

輸出結(jié)果如下所示,呈現(xiàn)一條曲線,因?yàn)樽ト〉脑u(píng)論基本都是好評(píng),所以分?jǐn)?shù)基本接近于1.0,而真實(shí)分析過程中存在好評(píng)、中評(píng)和差評(píng),曲線更加規(guī)律。

同時(shí),在做情感分析的時(shí)候,我看到很多論文都是將情感區(qū)間從[0, 1.0]轉(zhuǎn)換為[-0.5, 0.5],這樣的曲線更加好看,位于0以上的是積極評(píng)論,反之消極評(píng)論。修改代碼如下:

































# -*- coding: utf-8 -*-from snownlp import SnowNLPimport codecsimport os

#獲取情感分?jǐn)?shù)source = open('data.txt','r', encoding='utf-8')line = source.readlines()sentimentslist = []for i in line: s = SnowNLP(i) print(s.sentiments) sentimentslist.append(s.sentiments)

#區(qū)間轉(zhuǎn)換為[-0.5, 0.5]result = []i = 0while i<len(sentimentslist): result.append(sentimentslist[i]-0.5) i = i + 1

#可視化畫圖import matplotlib.pyplot as pltimport numpy as npplt.plot(np.arange(0, 356, 1), result, 'k-')plt.xlabel('Number')plt.ylabel('Sentiment')plt.title('Analysis of Sentiments')plt.show()

繪制圖形如下所示:

3.情感時(shí)間分布

最后補(bǔ)充隨時(shí)間分布的情感分?jǐn)?shù)相關(guān)建議,讀者可能也發(fā)現(xiàn)抓取的博客存在重復(fù)、時(shí)間不均衡等現(xiàn)象。微博數(shù)據(jù)還是非常不好抓取,數(shù)據(jù)卡住了很多人,也請(qǐng)讀者深入分析下。

(1) 情感分析通常需要和評(píng)論時(shí)間結(jié)合起來,并進(jìn)行輿情預(yù)測(cè)等,建議讀者嘗試將時(shí)間結(jié)合。比如王樹義老師的文章《基于情感分類的競(jìng)爭(zhēng)企業(yè)新聞文本主題挖掘》。

(2) 情感分析也是可以進(jìn)行評(píng)價(jià)的,我們前面抓取的分為5星評(píng)分,假設(shè)0-0.2位一星,0.2-0.4位二星,0.4-0.6為三星,0.6-0.8為四星,0.8-1.0為五星,這樣我們可以計(jì)算它的準(zhǔn)確率,召回率,F(xiàn)值,從而評(píng)論我的算法好壞。

(3) 作者還有很多情感分析結(jié)合冪率分布的知識(shí),因?yàn)樾枰獙懳恼?,這里暫時(shí)不進(jìn)行分享,但是這篇基礎(chǔ)文章對(duì)初學(xué)者仍然有一定的幫助。

(4) BosonNLP也是一個(gè)比較不錯(cuò)的情感分析包,建議感興趣的讀者學(xué)習(xí),它提供了相關(guān)的詞典,如下:https:///dev/resource。

(5) 讀者如果不太擅長(zhǎng)寫代碼,可以嘗試使用情感分析系統(tǒng)。http://ictclas./nlpir/

  

原文鏈接:

https://blog.csdn.net/Eastmount/article/details/104995419

【END】

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多