爬了菊姐2W條微博評論,竟發(fā)現(xiàn)“菊粉”都是這樣的人?。ǜ酱a)
原創(chuàng)【51CTO.com原創(chuàng)稿件】最近一段時間,《創(chuàng)造101》很火,這個火是可以理解的,畢竟這是中國首部女團節(jié)目。但是還有一個人不知道為啥突然也火了,那就是我們的菊姐。
關(guān)于菊姐為什么會火,網(wǎng)上有很多文章,我就不再贅述了。今天我們就來做一份菊粉陶淵明的用戶畫像,看看那些 Pick 菊姐的人都有什么特質(zhì)?
先來看看百度指數(shù),通過百度指數(shù)我們看出,菊姐的搜索熱度在 5 月 30 開始出現(xiàn)頂峰,5 月 31 開始回落。
王菊百度指數(shù)
再來看看微信指數(shù),與百度指數(shù)趨勢基本一致,但起伏感要稍強于百度指數(shù)。
王菊微信指數(shù)
我們再來看看菊姐的需求圖譜,即與菊姐相關(guān)的話題都有哪些。
王菊需求圖譜
相關(guān)詞主要有:創(chuàng)造101,王菊,王菊舊照,王菊年齡,看來大家很關(guān)心菊姐的個人信息哈,尤其是舊照。
王菊新舊照
看看菊姐以前的照片,再看看現(xiàn)在的,我只想問一句,菊姐這些年都經(jīng)歷了什么?
了解了這些以后,我們切換到今天的主題,菊粉到底都是哪些人?于是我用 Python 爬了菊姐的兩萬條微博評論,并做了分析!
數(shù)據(jù)抓取
爬取數(shù)據(jù)來源于王菊最新微博評論數(shù)據(jù),本次數(shù)據(jù)采集的思路主要是:
- 先獲取王菊最新幾條(關(guān)于創(chuàng)造101話題)的微博評論 url
- 然后依次去遍歷每條 url 下面的留言以及 user_id
- 在拿到 user_id 以后再去依次遍歷每個用戶的基本信息
具體實現(xiàn)代碼如下:
#導(dǎo)入所需庫
import json
import time
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
import squarify
from matplotlib.patches import Polygon
from mpl_toolkits.basemap import Basemap
from matplotlib.collections import PatchCollection
#獲取每條微博評論的url參數(shù)
def get_comment_parameter():
url = 'https://m.weibo.cn/api/container/getIndex?uid=1773294041&luicode=10000011&lfid=100103type%3D1%26q%3D%E7%8E%8B%E8%8F%8A&\
featurecode=20000320&type=uid&value=1773294041&containerid=1076031773294041'
c_r = requests.get(url)
for i in range(2,11):
c_parameter = (json.loads(c_r.text)["data"]["cards"][i]["mblog"]["id"])
comment_parameter.append(c_parameter)
return comment_parameter
if __name__ == "__main__":
comment_parameter = []#用來存放微博url參數(shù)
comment_url = []#用來存放微博url
user_id = []#用來存放user_id
comment = []#用來存放評論
containerid = []#用來存放containerid
feature = []#用來存放用戶信息
id_lose = []#用來存放訪問不成功的user_id
get_comment_parameter()
#獲取每條微博評論url
c_url_base = 'https://m.weibo.cn/api/comments/show?id='
for parameter in comment_parameter:
for page in range(1,101):#提前知道每條微博只可抓取前100頁評論
c_url = c_url_base + str(parameter) + "&page=" + str(page)
comment_url.append(c_url)
#獲取每個url下的user_id以及評論
for url in comment_url:
u_c_r = requests.get(url)
try:
for m in range(0,9):#提前知道每個url會包含9條用戶信息
one_id = json.loads(u_c_r.text)["data"]["data"][m]["user"]["id"]
user_id.append(one_id)
one_comment = json.loads(u_c_r.text)["data"]["data"][m]["text"]
comment.append(one_comment)
except:
pass
#獲取每個user對應(yīng)的containerid
user_base_url = "https://m.weibo.cn/api/container/getIndex?type=uid&value="
for id in set(user_id):#需要對user_id去重
containerid_url = user_base_url + str(id)
try:
con_r = requests.get(containerid_url)
one_containerid = json.loads(con_r.text)["data"]['tabsInfo']['tabs'][0]["containerid"]
containerid.append(one_containerid)
except:
containerid.append(0)
#獲取每個user_id對應(yīng)的基本信息
#這里需要設(shè)置cookie和headers模擬請求
user_agent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"
headers = {"User-Agent":user_agent}
m = 1
for num in zip(user_id,containerid):
url = "https://m.weibo.cn/api/container/getIndex?uid="+str(num[0])+"&luicode=10000011&lfid=100103type%3D1%26q%3D&featurecode=20000320&type=uid&value="+str(num[0])+"&containerid="+str(num[1])
try:
r = requests.get(url,headers = headers,cookies = cookie)
feature.append(json.loads(r.text)["data"]["cards"][1]["card_group"][1]["item_content"].split(" "))
print("成功第{}條".format(m))
m = m + 1
time.sleep(1)
except:
id_lose.append(num[0])
#將featrue建立成DataFrame結(jié)構(gòu)便于后續(xù)分析
user_info = pd.DataFrame(feature,columns = ["性別","年齡","星座","國家城市"])
數(shù)據(jù)預(yù)處理
根據(jù)用戶基本信息的顯示順序,性別、年齡、星座、國家城市,主要用了以下幾方面的數(shù)據(jù)處理邏輯:
- 對于國家列為空,星座列不空且不包含座字,則認為是國家城市名,則把星座列賦值給國家城市列。
- 對于國家列為空,星座列也為空,年齡列不為空且不包含歲或座字,則把年齡列賦值給國家城市列。
- 對于星座列為空,但是年齡列包含座字,則把年齡列賦值給星座列。
- 對于星座列不包含座的,全部賦值為“未知”。
- 對于年齡列不包含歲的,全部賦值為“999歲”(為便于后續(xù)好篩選)。
- 對于國家列為空的,全部賦值為“其他”。
具體處理代碼如下:
#數(shù)據(jù)清洗
user_info1 = user_info[(user_info["性別"] == "男") | (user_info["性別"] == "女")]#去除掉性別不為男女的部分
user_info1 = user_info1.reindex(range(0,5212))#重置索引
user_index1 = user_info1[(user_info1["國家城市"].isnull() == True)&(user_info1["星座"].isnull() == False)
&(user_info1["星座"].map(lambda s:str(s).find("座")) == -1)].index
for index in user_index1:
user_info1.iloc[index,3] = user_info1.iloc[index,2]
user_index2 = user_info1[((user_info1["國家城市"].isnull() == True)&(user_info1["星座"].isnull() == True)
&(user_info1["年齡"].isnull() == False)&(user_info1["年齡"].map(lambda s:str(s).find("歲")) == -1))].index
for index in user_index2:
user_info1.iloc[index,3] = user_info1.iloc[index,1]
user_index3 = user_info1[((user_info1["星座"].map(lambda s:str(s).find("座")) == -1)&
(user_info1["年齡"].map(lambda s:str(s).find("座")) != -1))].index
for index in user_index3:
user_info1.iloc[index,2] = user_info1.iloc[index,1]
user_index4 = user_info1[(user_info1["星座"].map(lambda s:str(s).find("座")) == -1)].index
for index in user_index4:
user_info1.iloc[index,2] = "未知"
user_index5 = user_info1[(user_info1["年齡"].map(lambda s:str(s).find("歲")) == -1)].index
for index in user_index5:
user_info1.iloc[index,1] = "999歲"
user_index6 = user_info1[(user_info1["國家城市"].isnull() == True)].index
for index in user_index6:
user_info1.iloc[index,3] = "其他"
評論多為褒義詞
我們抓取了菊姐的最新微博評論,將評論分詞以后制作成如下詞云圖,代碼如下:
import fool
from collections import Counter
from PIL import Image,ImageSequence
from wordcloud import WordCloud,ImageColorGenerator
#因留言結(jié)構(gòu)比較亂,所以先保存到本地做進一步處理
pd.DataFrame(comment).to_csv(r"C:\Users\zhangjunhong\Desktop\comment.csv")
#處理完以后再次載入進來
comment_data = pd.read_excel(r"C:\Users\zhangjunhong\Desktop\comment.xlsx")
#將數(shù)據(jù)轉(zhuǎn)換成字符串
text = (",").join(comment_data[0])
#進行分詞
cut_text = ' '.join(fool.cut(text))
#將分詞結(jié)果進行計數(shù)
c = Counter(cut_text)
c.most_common(500)#挑選出詞頻最高的500詞
#將結(jié)果導(dǎo)出到本地進行再一次清洗,刪除一些符號詞
pd.DataFrame(c.most_common(500)).to_excel(r"C:\Users\zhangjunhong\Desktop\fenci.xlsx")
image = Image.open('C:/Users/zhangjunhong/Desktop/圖片1.png')#作為背景形狀的圖
graph = np.array(image)
#參數(shù)分別是指定字體、背景顏色、最大的詞的大小、使用給定圖作為背景形狀
wc = WordCloud(font_path = "C:\\Windows\\Fonts\\simkai.ttf", background_color = 'White', max_words = 150, mask = graph)
fp = pd.read_csv(r"C:\Users\zhangjunhong\Desktop\da200.csv",encoding = "gbk")#讀取詞頻文件
name = list(fp.name)#詞
value = fp.time#詞的頻率
dic = dict(zip(name, value))#詞頻以字典形式存儲
wc.generate_from_frequencies(dic)#根據(jù)給定詞頻生成詞云
image_color = ImageColorGenerator(graph)
plt.imshow(wc)
plt.axis("off")#不顯示坐標(biāo)軸
plt.show()
wc.to_file('C:/Users/zhangjunhong/Desktop/wordcloud.jpg')
分詞沒有用 jieba 分詞,而是用了 fool,據(jù)稱是最準(zhǔn)確的中文分詞包。
GitHub 地址:??https://github.com/rockyzhengwu/FoolNLTK??
排名前三的熱詞分別是:“加油”、“哈哈”、“菊姐”,可以看出大家對菊姐的態(tài)度大多還是支持的態(tài)度。
男女比例 1:2
繪制男女比例的餅圖
ax = user_info1["性別"].value_counts(normalize = True).plot.pie(title = "菊粉男女分布",autopct='%.2f')
菊粉性別分布
既然是女團節(jié)目,按理來說應(yīng)該男生人數(shù)要多于女生的(為什么這么說,大家應(yīng)該都懂哈),但再想想,菊姐并不是因為長相甜美而走紅,那男生比例少一點也就可以理解了。
關(guān)于女性,菊姐經(jīng)典語錄:精神獨立和經(jīng)濟獨立,對于女生而言是很重要的。
有可能是是菊姐的獨立女性做自己的形象觸動了各位小姐姐的內(nèi)心。
20-25 歲成中堅力量
#將把年齡從字符串變成數(shù)字
user_info1["age_1"] = [int(age[:-1]) for age in user_info1["年齡"]]
#對年齡進行分組
bins = (0,10,20,25,30,100,1000)#將年齡進行區(qū)間切分
cut_bins = pd.cut(user_info1["age_1"],bins = bins,labels = False)
ax = cut_bins[cut_bins < 5].value_counts(normalize =True).plot.bar(title = "菊粉年齡分布")#將大于100歲的過濾掉
ax.set_xticklabels(["20-25歲","10-20歲","25-30歲","0-10歲","30+"],rotation = 0)
菊粉年齡分布
如上圖,還有 0-10 歲的粉絲,比較神奇,不過我更愿意相信這部分是因為用戶隨意填寫導(dǎo)致的。還好只有約 10% 的比例,影響不大。
20-25 歲這一部分開始對新生事物有自己的判斷,比較喜歡有個性的東西,對美的定義也是各不相同,可能菊姐的特性在他們眼里就是最美的吧。
還有 30 多歲的大哥哥大姐姐們,看來菊姐的某些特質(zhì)引發(fā)了大哥哥大姐姐們的共鳴。
海外粉絲數(shù)位居榜首
#將國家和城市進行分列
country_data = pd.DataFrame([country.split(" ") for country in user_info1["國家城市"]],columns = ["省份","城市"])
#將國家和城市與user表合并
user_data = pd.merge(user_info1,country_data,left_index = True,right_index = True,how = "left")
#按省份進行分組計數(shù)
shengfen_data = user_data.groupby("省份")["性別"].count().reset_index().rename(columns = {"性別":"人次"})
#導(dǎo)入解析好的省份經(jīng)緯度信息
location = pd.read_table(r"C:\Users\zhangjunhong\Desktop\latlon_106318.txt",sep = ",")
#將省份數(shù)據(jù)和經(jīng)緯度進行匹配
location_data = pd.merge(shengfen_data,location[["關(guān)鍵詞","地址","谷歌地圖緯度","谷歌地圖經(jīng)度"]],
left_on = "省份",right_on = "關(guān)鍵詞",how = "left")
#進行地圖可視化
fig = plt.figure(figsize=(16,12))
ax = fig.add_subplot(111)
basemap = Basemap(llcrnrlon= 75,llcrnrlat=0,urcrnrlon=150,urcrnrlat=55,projection='poly',lon_0 = 116.65,lat_0 = 40.02,ax = ax)
basemap.readshapefile(shapefile = "C:/Users/zhangjunhong/Desktop/CHN_adm/CHN_adm1",name = "china")
def create_great_points(data):
lon = np.array(data["谷歌地圖經(jīng)度"])
lat = np.array(data["谷歌地圖緯度"])
pop = np.array(data["人次"],dtype=float)
name = np.array(data["地址"])
x,y = basemap(lon,lat)
for lon,lat,pop,name in zip(x,y,pop,name):
basemap.scatter(lon,lat,c = "#778899",marker = "o",s = pop*10)
plt.text(lon,lat,name,fontsize=10,color = "#DC143C")
create_great_points(location_data)
plt.axis("off") #關(guān)閉坐標(biāo)軸
plt.savefig("C:/Users/zhangjunhong/Desktop/itwechat.png") #保存圖表到本地
plt.show() #顯示圖表
??
菊粉全國分布
ax = shengfen_data[shengfen_data["省份"] != "其他"].sort_values(by = "人次",ascending = False).head(10).plot.barh(legend = False,color = "#BF0003",title = "菊粉Top10省份")
ax.set_yticklabels(["海外","廣東","北京","浙江","上海","四川","江蘇","山東","湖北","福建"])
菊粉分布 Top10 省份
這里的海外是指大陸+港澳臺以外的其他所有地方。除海外用戶以外就北上廣的用戶最多了,這些地方的互聯(lián)網(wǎng)用戶基數(shù)本來就大。
#Top10城市圖表繪制
chengshi_data = user_data.groupby("城市")["性別"].count().reset_index().rename(columns = {"性別":"人次"})
ax = chengshi_data[chengshi_data["城市"] != "其他"].sort_values(by = "人次",ascending = False).head(10).plot.barh(legend = False,color = "#BF0003",title = "菊粉Top10城市")
ax.set_yticklabels(["廣州","成都","杭州","武漢","長沙","朝陽區(qū)","西安","深圳","美國","福州"])
菊粉分布 Top10 城市
因為北京上海比較特殊,北京上海的一些區(qū)相當(dāng)于北京上海這兩個省下面的市區(qū),所以你會看到一些北京上海的區(qū)域也進入了榜單,比如說朝陽群眾。
摩羯座粉絲人最多
#菊粉星座樹地圖繪制
# 創(chuàng)建數(shù)據(jù)
xingzuo = user_info1["星座"].value_counts(normalize = True).index
size = user_info1["星座"].value_counts(normalize = True).values
rate = np.array(["34%","6.93%","5.85%","5.70%","5.62%","5.31%","5.30%","5.24%","5.01%","4.78%","4.68%","4.36%"])
# 繪圖
colors = ['steelblue','#9999ff','red','indianred',
'green','yellow','orange']
plot = squarify.plot(sizes = size, # 指定繪圖數(shù)據(jù)
label = xingzuo, # 指定標(biāo)簽
color = colors, # 指定自定義顏色
alpha = 0.6, # 指定透明度
value = rate, # 添加數(shù)值標(biāo)簽
edgecolor = 'white', # 設(shè)置邊界框為白色
linewidth =3 # 設(shè)置邊框?qū)挾葹?
)
# 設(shè)置標(biāo)簽大小
plt.rc('font', size=10)
# 設(shè)置標(biāo)題大小
plt.title('菊粉星座分布',fontdict = {'fontsize':12})
# 去除坐標(biāo)軸
plt.axis('off')
# 去除上邊框和右邊框刻度
plt.tick_params(top = 'off', right = 'off')
菊粉星座分布
除了未知星座以外,菊姐的粉絲中摩羯座的粉絲最多。我們看看摩羯座都有哪些特性。
摩羯座男性:摩羯座男生特別細心有責(zé)任感,對待誰,都會問心無愧,仁至義盡。這是摩羯座整個人生當(dāng)中的核心信條,只有在做到了自己該做到的事情之后摩羯座才能夠坦然的去批評別人,去申述理論,因此摩羯座一直都站在正義的一方和大義的立場上。
摩羯座女性:一板一眼的,戴著厚厚的平底眼鏡,梳著中規(guī)中矩的頭發(fā),就連自己的衣著,也盡量以不突出不惹人矚目為目標(biāo),摩羯座的女生就是這樣,貌似不起眼的外表,耐力驚人(怎么感覺是在說菊姐)。
摩羯座可以連續(xù)十年作同一件普通簡單的事情,只是單一重復(fù)仍然感覺樂趣無窮,這樣的事情,在別的星座女生看來,簡直不敢想象,不過摩羯座卻能完成,而且津津有味。
菊姐語錄:沒有奇跡,只有累積,更是完美匹配了摩羯女十年做同一件事情的堅強毅力。
"陶淵明"究竟是何方神圣
最后將菊粉上面的幾個特征綜合了做了一個詞云圖,得到了菊粉的一個大概畫像,代碼如下:
image = Image.open('C:/Users/zhangjunhong/Desktop/圖片1.png')#作為背景形狀的圖
graph = np.array(image)
#參數(shù)分別是指定字體、背景顏色、最大的詞的大小、使用給定圖作為背景形狀
wc = WordCloud(font_path = "C:\\Windows\\Fonts\\simkai.ttf", background_color = 'White', max_words = 150, mask = graph)
name = ["女性","摩羯座","20歲","21歲","22歲","23歲","24歲","25歲","廣州","杭州","成都","武漢","長沙","上海","北京","海外","美國","深圳"]
value = [20,20,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10]#詞的頻率
dic = dict(zip(name, value))#詞頻以字典形式存儲
wc.generate_from_frequencies(dic)#根據(jù)給定詞頻生成詞云
image_color = ImageColorGenerator(graph)
plt.imshow(wc)
plt.axis("off")#不顯示坐標(biāo)軸
plt.show()
wc.to_file('C:/Users/zhangjunhong/Desktop/wordcloud.jpg')
菊粉畫像
通過該詞云圖可以看出,“陶淵明”主要有以下特質(zhì):
- 女性
- 20-25 歲
- 海外、北京、上海、廣州
- 摩羯座
關(guān)于菊粉陶淵明的用戶畫像就到這了,關(guān)于菊姐你有什么想說的,我們留言區(qū)見。
知名互聯(lián)網(wǎng)公司數(shù)據(jù)分析師,擅長 Python、SQL、Tableau 等,對機器學(xué)習(xí)、網(wǎng)絡(luò)爬蟲和數(shù)據(jù)分析等領(lǐng)域都比較熟悉。個人微信公眾號:張俊紅(ID:zhangjunhong0428),定期推送機器學(xué)習(xí)、網(wǎng)絡(luò)爬蟲、數(shù)據(jù)分析、Python 編程系列文章。
【51CTO原創(chuàng)稿件,合作站點轉(zhuǎn)載請注明原文作者和出處為51CTO.com】