用python對鹿晗、關曉彤微博進行情感分析 哭著學習學習~
前言:本文主要涉及知識點包括新浪微博爬蟲、python對資料庫的簡單讀寫、簡單的列表資料去重、簡單的自然語言處理(snowNLP模組、機器學習)。適合有一定程式設計基礎,並對python有所瞭解的盆友閱讀。
相信最近科技圈都在調侃一件事:10月8日中午的一條微博,引發了一場新浪微博使用者們(尤其是女性使用者)之間的軒然大波,導致新浪微博癱瘓。
這條微博的始作俑者,就是全球超人氣偶像明星鹿晗。
程式設計師們紛紛開啟了科♂學地討論:
鹿晗是如何將微博伺服器搞炸的
微博工程師是如何一邊結婚一邊加班的
淘寶程式設計師是如何原諒鹿晗的
在這一刻,全世界都知道鹿晗戀愛了。
全球的女鹿飯們一起失戀了。
那麼鹿晗的粉絲們情緒如何呢?我們來分析一下鹿晗戀情微博的評論,分析評論粉絲們的心情狀態,且聽我娓娓道來。
1.新浪微博API
在經歷了幾次爬蟲被禁的悲痛(真的很痛)之後,我學會了在爬網站之前先查有沒有API的“優良”習慣。新浪作為一個大廠,怎麼會不推出新浪微博API呢,面向開發者新浪有自己的開放平臺,這裡是python呼叫微博API的方法,下面是通過登入App_key和App_secret方式訪問微博API的程式碼,程式碼是基於py2的。py3對weibo模組使用存在一定問題。
from weibo import APIClient
import webbrowser
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
APP_KEY = '你的App Key ' #獲取的App Key
APP_SECRET = '你的AppSecret' #獲取的AppSecret
CALLBACK_URL = 'https://api.weibo.com/oauth2/default.html' #回撥連結
client = APIClient(app_key=APP_KEY, app_secret=APP_SECRET, redirect_uri=CALLBACK_URL)
url = client.get_authorize_url()
webbrowser.open_new(url) #開啟預設瀏覽器獲取code引數
print '輸入url中code後面的內容後按回車鍵:'
code = raw_input()
r = client.request_access_token(code)
access_token = r.access_token
expires_in = r.expires_in
client.set_access_token(access_token, expires_in)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
知道如何登入API了,辣麼如何呼叫API爬單條微博的評論呢?一行程式碼搞定。
r = client.comments.show.get(id = 4160547165300149,count = 200,page = 1)
- 1
所有關於單條微博的評論資訊都在r.comments中了,這裡需要對照微博API文件,微博API有宣告呼叫微博評論API需要獲取使用者授權,但是捏,只要知道單條微博的id,就可以呼叫這個API了,關於單條微博的id如何獲取在後面會說(小聲一點,千萬別讓微博知道,萬一封了呢)。
按照client.介面名.get(請求引數)的方式獲取API,獲取API後的規格可在介面詳情中檢視,文件中有給出返回結果的示例。
文件中也給出了關鍵資料的json介面名稱。
如果我們要獲取微博評論的內容,只需要呼叫text介面即可。
for st in r.comments:
text = st.text
- 1
- 2
2.微博爬蟲
通過呼叫新浪微博API的方式,我們就可以簡單獲取單條微博的評論資訊了,為啥說簡單呢,因為人紅資訊貴啊!你以為大V的微博就這麼免費的給你API呼叫了嗎,非認證應用開發者單日只能請求千次API,這對像鹿晗這樣單條微博幾十萬評論的大V來說…太少了(TT)
所以捏,還是要寫微博爬蟲。
正所謂,知己知彼百戰不殆,新浪作為大廠,怎麼說也是身經百戰,必定是經歷了無數場爬蟲與反爬之間的戰爭,必然有著健全的反爬策略。正所謂,強敵面前,繞道而行,有位大佬說得好,爬網站,先爬移動端:https://m.weibo.cn/
登入微博後,進入到鹿晗公佈戀情的微博中去,_(:зゝ∠)_ 已經有200w+評論了,可以看到安靜的微博下粉絲們不安的心…
移動端微博的網址顯得肥腸簡單,不似PC端那麼複雜而不明邏輯:https://m.weibo.cn/status/4160547165300149 多點幾條微博就可以知道status後面的數字,就是單條微博的id了。
評論裡包含了熱門評論和最新評論倆種,但無論是哪種評論,繼續往下翻網址都不會變化。在chrome瀏覽器右鍵“檢查”,觀察network變化。
從network的xhr檔案中,可以得知熱門評論的變化規律是:
'https://m.weibo.cn/single/rcList?format=cards&id=' + 單條微博id + '&type=comment&hot=1&page=' + 頁碼
- 1
最新評論的變化規律是:
'https://m.weibo.cn/api/comments/show?id=' + 單條微博id + '&page=' + 頁碼
- 1
接下來就是套路了,偽裝瀏覽器header,讀取json檔案,遍歷每一頁…這都不是重點!直接上程式碼\~這裡開始是py3的程式碼了~
import re,time,requests,urllib.request
weibo_id = input('輸入單條微博ID:')
# url='https://m.weibo.cn/single/rcList?format=cards&id=' + weibo_id + '&type=comment&hot=1&page={}' #爬熱門評論
url='https://m.weibo.cn/api/comments/show?id=' + weibo_id + '&page={}' #爬時間排序評論
headers = {
'User-agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:55.0) Gecko/20100101 Firefox/55.0',
'Host' : 'm.weibo.cn',
'Accept' : 'application/json, text/plain, */*',
'Accept-Language' : 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Accept-Encoding' : 'gzip, deflate, br',
'Referer' : 'https://m.weibo.cn/status/' + weibo_id,
'Cookie' : '登入cookie資訊',
'DNT' : '1',
'Connection' : 'keep-alive',
}
i = 0
comment_num = 1
while True:
# if i==1: #爬熱門評論
# r = requests.get(url = url.format(i),headers = headers)
# comment_page = r.json()[1]['card_group']
# else:
# r = requests.get(url = url.format(i),headers = headers)
# comment_page = r.json()[0]['card_group']
r = requests.get(url = url.format(i),headers = headers) #爬時間排序評論
comment_page = r.json()['data']
if r.status_code ==200:
try:
print('正在讀取第 %s 頁評論:' % i)
for j in range(0,len(comment_page)):
print('第 %s 條評論' % comment_num)
user = comment_page[j]
comment_id = user['user']['id']
print(comment_id)
user_name = user['user']['screen_name']
print(user_name)
created_at = user['created_at']
print(created_at)
text = re.sub('<.*?>|回覆<.*?>:|[\U00010000-\U0010ffff]|[\uD800-\uDBFF][\uDC00-\uDFFF]','',user['text'])
print(text)
likenum = user['like_counts']
print(likenum)
source = re.sub('[\U00010000-\U0010ffff]|[\uD800-\uDBFF][\uDC00-\uDFFF]','',user['source'])
print(source + '\r\n')
comment_num+=1
i+=1
time.sleep(3)
except:
i+1
pass
else:
break
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
這裡有幾點說明:
1.設定爬取間隔時間之後,微博爬蟲被禁的概率降低了很多(特別是晚上)
2.新浪每次返回的json資料條數隨機,所以翻頁之後會出現資料重複的情況,所以用到了資料去重,這會在後面說。
3.在text和source中添加了去除emoji表情的程式碼(折騰了很久寫不進資料庫,差點就從刪庫到跑路了/(ㄒoㄒ)/),同時也去除了摻雜其中的回覆他人的html程式碼。
4.我只寫了讀取資料,沒有寫如何儲存,因為我們要用到數!據!庫!辣!(這是重點!敲黑板)
3.python中資料庫的讀取與寫入
雖然微博爬蟲大大提高了資料獲取量,但也因為是爬蟲而容易被新浪封禁。這裡結束迴圈的判斷是網路狀態不是200,但當微博發現是爬蟲時,微博會返回一個網頁,網頁中什麼實質內容都木有,這時候程式就會報錯,而之前爬到的資料,就啥也沒有了。
但是如果爬一會,儲存一次資料,這資料量要一大起來…冷冷的檔案在臉上胡亂地拍…我的心就像被…這時候我們就需要用到資料庫了。
資料庫,顧名思義,就是存放資料的倉庫,資料庫作為一個發展了60多年的管理系統,有著龐大的應用領域和複雜的功能……好了我編不下去了。
在本文中,資料庫的主要作用是AI式的excel表格(●—●)。在爬蟲進行的過程中,爬到一個數就存進去,爬到一個數就存進去,即使爬蟲程式執行中斷,中斷前爬到的資料都會存放在資料庫中。
大多數資料庫都能與python對接使用的,米醬知道的有mysql、sqlite、mongodb、redis。這裡用的是mysql,mac上mysql的安裝,管理資料庫的軟體Navicat使用幫助,其他系統自己找吧,安裝使用過程中有啥問題,請不要來找我(逃
根據上面的程式碼,在navicat中建立資料庫、表和域以及域的格式。在Python程式中新增程式碼。
conn =pymysql.connect(host='伺服器IP(預設是127.0.0.1)',user='伺服器名(預設是root)',password='伺服器密碼',charset="utf8",use_unicode = False) #連線伺服器
cur = conn.cursor()
sql = "insert into nlp.love_lu(comment_id,user_name,created_at,text,likenum,source) values(%s,%s,%s,%s,%s,%s)" #格式是:資料名.表名(域名)
param = (comment_id,user_name,created_at,text,likenum,source)
try:
A = cur.execute(sql,param)
conn.commit()
except Exception as e:
print(e)
conn.rollback()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
執行python程式,大概爬了1w條實時評論,在進行下一步研究之前,我們還要將資料庫中的內容讀取出來,python中資料庫的讀取程式碼也很簡單。
conn =pymysql.connect(host='伺服器IP',user='使用者名稱',password='密碼',charset="utf8") #連線伺服器
with conn:
cur = conn.cursor()
cur.execute("SELECT * FROM nlp.love_lu WHERE id < '%d'" % 10000)
rows = cur.fetchall()
- 1
- 2
- 3
- 4
- 5
這樣之前爬取的資訊就被讀取出來了,但是前面也說了,微博爬蟲翻頁時返回資料條數隨機,所以會出現重複的狀況,所以讀取之後,需要用if…not in語句進行一個數據去重。
for row in rows:
row = list(row)
del row[0]
if row not in commentlist:
commentlist.append([row[0],row[1],row[2],row[3],row[4],row[5]])
- 1
- 2
- 3
- 4
- 5
完整程式碼在文末。
4.自然語言處理NLP
NLP是人工智慧的一個領域,可以通過演算法的設計讓機器理解人類語言,自然語言也屬於人工智慧中較為困難的一環,像中文這麼博大精深、變幻莫測的語言更是NLP中的一大難點,python中有很多NLP相關的模組,有興趣的盆友可以通過用python實現簡單的文字情感分析初探NLP。
我參(ban)考(yun)了一些現成的情感分析演算法,對爬取的評論進行分析,錯誤率肥腸高_(:зゝ∠)_ ,這可腫麼辦?難道要重新設計演算法?米醬彷彿遇到了人生中第一個因為語文沒學好而引發的重大問題……
當然像米醬這樣靈(lan)活(duo)的姑娘,自然是很快發現了python中較為出名的一箇中文NLP庫:snowNLP。snowNLP呼叫的方法比較簡單,原始碼中詳細解釋了呼叫方法,和生成結果。
defsnowanalysis(textlist):
sentimentslist = []
for li in textlist:
s = SnowNLP(li)
print(li)
print(s.sentiments)
sentimentslist.append(s.sentiments)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
這段程式碼中獲取了讀取資料庫後由評論主體text生成的列表檔案,並依次對每一個評論進行情感值分析。snowNLP能夠根據給出的句子生成一個0-1之間的值,當值大於0.5時代表句子的情感極性偏向積極,當分值小於0.5時,情感極性偏向消極,當然越偏向倆頭,情緒越明顯咯,讓我們來看看測試評論的結果。
可以從文字內容和下面對應的數值看出,祝福或者表現的積極的情緒,分值大多高於0.5,而期盼分手或者表達消極情緒的分值,大多低於0.5。分析結果中也存在一定的誤差,可以通過訓練對演算法進行優化,米醬語文不好就不瞎搞了…(逃
5.分析結果
讓我們來看看本次分析的結果(●—●)。
plt.hist(sentimentslist,bins=np.arange(0,1,0.02))
plt.show()
- 1
- 2
對上節經過處理得到的情感值列表進行統計,並生成分佈圖。下圖資料採集時間10月9日19時,採集評論1w條。
~鹿晗宣佈戀愛微博評論情感值分佈~
再看看關曉彤迴應的微博情況。
~關曉彤對應微博評論情感值分佈~
根據這兩張圖,可以看到情感值在接近0、1兩端以及0.5左右位置頻率較高,說明粉絲們對於此類事件的情緒無論是積極還是消極都是比較明顯的。但也可以看出,積極的情緒更甚於消極的情緒。
我又對評論中出現的微博表情進行了統計。
給鹿晗的評論中表情的數量是關曉彤的近3倍,而排在第一位的,都是 [加油],可以看到粉絲們對鹿晗的戀情還是支援居多的,當然也不乏有些人想要 [bm投訴] 主角們了,也有部分人感到 [悲傷],想要冷靜一下 [別煩我]。
再對評論內容進行一下詞雲分析。
~鹿晗宣佈戀愛微博評論詞雲~
~關曉彤對應微博評論詞雲~
在鹿晗的微博下面出現了大量的祝福、支援、一起等詞彙,也有一些為什麼、不配、分手之類質疑的聲音,在關曉彤的微博下面也存在相同的詞彙,但是好像還有大量的關於熱巴、李易峰的字眼,看來倆位都有緋聞CP呀。
你們猜詞雲的背景圖是什麼?米醬就不說了,你們自己感受。
建了一個qq群,歡迎各位來交♂流學♀習→python交友娛樂會所:613176398
為了營造良好的交流環境,入群需回答問題:匹配資訊用什麼表示式,請認真回答,否則會被拒絕的哦~