當前位置:
首頁 > 科技 > Python 爬取 B 站數據分析,宋智孝李光洙誰最受中國粉絲喜愛

Python 爬取 B 站數據分析,宋智孝李光洙誰最受中國粉絲喜愛

作者 | 左伊雅

責編 | 胡巍巍

《Running Man》是韓國SBS電視台在《星期天真好》單元推出的戶外競技真人秀節目。

節目致力於打造一個不同於Real variety的新型態娛樂節目。每期有不同的主題,由不同的嘉賓參演,分為不同的隊伍進行比賽,通過完成各種遊戲任務,最後獲勝一方將獲得稱號或獎品。

成員組成包括原六位成員劉在石、池石鎮、金鐘國、HAHA(河東勛)、宋智孝、李光洙 ,以及兩位新成員全昭旻、梁世燦。

抓取數據

自從限韓令發布後,Running man在除B站以外的各大視頻網站均下架,所以本文從B站出發,抓取相關視頻的所有評論。

由於相關視頻非常多,本文選擇了最具代表性,點擊量觀看次數最多的視頻。

進入這個頁面後開始抓包(https://www.bilibili.com/video/av18089528?from=search&seid=16848360519725142300)。

不斷點擊下一頁,可以發現reply?callback=這個文件一直在出現。

打開其中一個文件以後可以看到每一面的評論都在裡面;只需構建出類似的URL就可以把所有的評論都爬下來啦。

分析一下這個URL:

https://api.bilibili.com/x/v2/replycallback=jQuery17201477141935656543_1541165464647&jsonp=jsonp&pn=368&type=1&oid=18089528&sort=0&_=1541165714862

pn是頁面數,_對應距離1971年1月1日的秒數,直接用time.time就可以獲得,其餘參數保持不變。數據格式是Json,但是B站有點小狡猾啊~

它把所有的Json數據都存在jQuery17201477141935656543_1541165464647這個裡面。

所以提取的時候要處理一下(Talk is cheap,show me the code)。

html=requests.get(url,headers=headers).text

html=json.loads(html.split("(",1))[1][:-1])

最後我們把所有的評論都抓取下來存入Excel中,數據格式是這樣子的:

寫入CSV的時候一定要記得encoding="utf-8",就因為少了這個,數據總會亂碼,因為各種奇葩的原因(點了一下,拉寬了一下,原地保存一下)。

數據清洗

對於B站的各種缺失數據,就直接用0替換;對於詩歌類的評論,它存到CSV時是一句佔一行,而它的其餘信息都會存到最後一行。

所以在處理時,把前面的n-1行打包append到n行的評論中,再把n-1行刪除;對於B站返回的時間(類似於1540882722);用time.strftime("%Y-%m-%d %H:%M:%S,time.localtime())變換成2018/11/12 22:15:15。

數據分析

清理後一共得到7513*11條數據,接下來對數據進行一些分析,數據分析通過Python和R完成。

男女分布

從餅圖可以看出,近六成的人選擇保密個人信息,公開信息顯示女生僅比男生多3%。這個結論是出乎意料的。原來不論男女都很喜歡Running man。

defmale(sex):

att=["男","女","保密"]

val=[]

foriinatt:

val.append(sex.count(i))

pie = Pie("","性別餅圖", title_pos="right", width=1200, height=600)

pie.add("", att, val, label_text_color=None, is_label_show=True, legend_orient="vertical",

is_more_utils=True, legend_pos="left")

pie.render("sexPie.html")

評論周分布

Running man在韓國的更新時間是每周天下午,但是要到周一B站才會有所更新。

因此從評論周分布圖可以看到,星期一的評論數是遠遠大於其他時間的,其次是星期二和星期天,正好在Runnning man 更新前後,對比其他時間段評論數有一定增長。

defana_week(week):

weeks=["星期天","星期一","星期二","星期三","星期四","星期五","星期六"]

output_file("week_bar.html")

count=[]

foriinsorted(set(week)):

ifnotnumpy.isnan(i):

count.append(week.count(i))

source = ColumnDataSource(data=dict(weeks=weeks, counts=count,color=["orange","yellowgreen","pink","darksalmon","lightgreen","paleturquoise","lightsteelblue"]))

p=figure(x_range=weeks, y_range=(,4000), plot_height=250, title="Week Counts",

toolbar_location=None, tools="")

p.vbar(x="weeks", top="counts", color="color",width=0.9, legend="Week", source=source)

p.legend.orientation ="horizontal"

p.legend.location ="top_right"

show(p)

評論時間分布

除了每周評論數,對於評論數的日趨勢也十分好奇,大家一般會在什麼時間段內觀看評論呢?

根據上圖可以看到,在6點以後迎來一個爆炸性增漲,在11點-13點之間達到峰值,其次是在15點-17點之間迎來第二波小高潮。

在晚間,除了20點有一定下降外,評論數都接近500條。而午夜評論數最少,不過還是有不少夜貓子啊。

def ana_hour(hour):

h,k=[],[]

foriinrange(len(hour)):

ifisinstance(hour[i],str):

h.append(hour[i][:2])

foriinsorted(set(h)):

k.append(h.count(i))

print(k)

output_file("hour_line.html")

p = figure(plot_width=400,title="各小時評論數", plot_height=400)

p.line(sorted(set(h)), k, line_width=2)

p.circle(sorted(set(h)), k, fill_color="white", size=8)

show(p)

評論字數與點贊數

對比每條評論的字數與點贊次數,從上圖可以看到,評論的字數越多,獲得贊的概率就越大:100字以上的評論獲得贊的平均次數遠高於100字以下的評論,而那些10個字以內的評論基本沒有獲得贊,所以只要你是認真評論寫出大家的心聲,就能獲得大家的認同。

def com_zan(com,zan):

q,w,e,r,t=[],[],[],[],[]

fori inrange(len(com)):

iflen(com[i])

q.append(zan[i])

if10

w.append(zan[i])

if50

e.append(zan[i])

if100

r.append(zan[i])

a=go.Box(y=q,name="0-10個字")

b=go.Box(y=w,name="10-50個字")

c=go.Box(y=e,name="50-100個字")

d=go.Box(y=r,name="100以上個字")

e=go.Box(y=zan,name="所有評論")

data=[a,b,e,c,d]

layout =go.Layout(legend=dict(font=dict(size=16)),orientation=270)

fig =go.Figure(data=data, layout=layout)

plotly.offline.plot(data)

情感分析

將大家的評論分別進行情感分析,越接近1說明正面情感越強烈;相反越靠近0負面情緒越強。

從上圖可以看到,雖然有近600人的評論是非常負能量,但是絕大多數的人都是1分、0.9分。

在Running man給我們帶來歡樂與感動的同時,大家對Running man是滿滿的寵愛啊。

def snownlp(com):

q=[]

foriincom:

s=SnowNLP(i)

q.append(round(s.sentiments,1))

emotion=[]

count=[]

foriinsorted(set(q)):

emotion.append(str(i))

count.append(q.count(i))

#count=[596,481,559,566,490,617,528,601,581,809,1685]

#emotion=["0.0","0.1","0.2","0.3","0.4","0.5","0.6","0.7","0.8","0.9","1.0"]

output_file("評論情感分析.html")

source = ColumnDataSource(data=dict(emotion=emotion, counts=count))

p = figure(x_range=emotion, y_range=(,2000), plot_height=250, title="評論情感分析",

toolbar_location=None, tools="")

p.vbar(x="emotion", top="counts", width=0.9, source=source)

p.legend.orientation ="horizontal"

show(p)

話題度排行

一直都很好奇在觀眾心中哪個mc的話題度最高,所以做了一個話題度排行。從上圖可以看到haha是最具話題性的mc(這個結果有點出乎意料呢)其次是李光洙和宋智孝。

因為筆者統計的是2018年的Running man ,所以Gary的數據是有點凄慘的。對比兩個新成員,全妹的話題度比世贊高的不是一點點。

defhot(com):

#print(com)

output_file("各成員話題度.html")

jzg=["金鐘國","鍾國","能力者"]

gary=["gary","狗哥"]

haha=["haha","HAHA","哈哈"]

qsm=["全昭敏","全妹","全昭body"]

lsz=["梁世贊","世贊","小不點"]

name=["池石鎮","劉在石","宋智孝","李光洙","金鐘國","gary","haha","全昭敏","梁世贊"]

csz,lzs,szx,lgz,jzg,gary,haha,qsm,lsz=[],[],[],[],[],[],[],[],[]

foriincom:

if"池石鎮"ini or"石鎮"ini or"鼻子"ini:

csz.append(i)

if"劉在石"inior"在石"inior"大神"inior"螞蚱"ini:

lzs.append(i)

if"宋智孝"inior"智孝"inior"懵智"inior"美懵"ini:

szx.append(i)

if"李光洙"inior"光洙"inior"一筐豬"ini:

lgz.append(i)

if"金鐘國"inior"鍾國"inior"能力者"ini:

jzg.append(i)

if"gary"ini or"狗哥"ini:

gary.append(i)

if"haha"inior"HAHA"inior"哈哈"ini:

haha.append(i)

if"全昭敏"inior"全妹"ini or"全昭body"ini:

qsm.append(i)

if"梁世贊"ini or"世贊"ini or"小不點"ini:

lsz.append(i)

count=[len(csz),len(lzs),len(szx),len(lgz),len(jzg),len(gary),len(haha),len(qsm),len(lsz)]

source = ColumnDataSource(data=dict(name=name, counts=count,color=["orange",

"yellowgreen","pink","darksalmon","lightgreen","paleturquoise","lightsteelblue",

"hotpink","yellow"]))

p = figure(x_range=name, y_range=(,600), plot_height=250, title="話題度排行",

toolbar_location=None, tools="")

p.vbar(x="name", top="counts", color="color", width=0.9, source=source)

p.legend.orientation ="horizontal"

show(p)

Running man一直都不缺CP,前有周一情侶Gary和宋智孝,權力夫婦劉在石和金鐘國,老年line劉在石和池石鎮,我兄我弟金鐘國和haha,背叛者聯盟必觸cross。

現在又有國民兄妹劉在石和全昭敏,麻浦兄妹宋智孝和haha,烤肉line金鐘國haha等等。

他們的關係錯綜複雜,所以筆者打算好好扒一扒觀眾眼中的各種line。

成員關係矩陣

滿分為100分,可以看到池石鎮和劉在石;劉在石和李光洙;金鐘國和宋智孝;Gary和宋智孝;haha和李光洙;全昭敏和宋智孝的相關性均非常高,其中Gary和宋智孝的相關性居然達到40,也就是說評論中如果有Gary那麼有四成的概率會出現宋智孝,周一情侶真的是深入人心。

其次是宋智孝和金鐘國,看來之前還一直有人說他倆會結婚也不是空穴來潮;而梁世贊與其餘成員的相關性都很高,這說明大家都不怎麼單獨提到他,希望世贊可以早日找到自己的定位;獲得觀眾的認可!

defnetwork_edg_csv(com):

df=pandas.DataFrame(columns=["池石鎮","劉在石","宋智孝","李光洙","金鐘國","gary","haha","全昭敏","梁世贊"],index=["池石鎮","劉在石","宋智孝","李光洙","金鐘國","gary","haha","全昭敏","梁世贊"])

df.loc[:,:]=0.0

foriincom:

if(iin"池石鎮"ini or"石鎮"ini or"鼻子"ini):

df["池石鎮"]["池石鎮"] = df["池石鎮"]["池石鎮"] +1

if("劉在石"inior"在石"inior"大神"inior"螞蚱"ini):

df["池石鎮"]["劉在石"] = df["池石鎮"]["劉在石"] +1

df["劉在石"]["池石鎮"] = df["劉在石"]["池石鎮"] +1

#成員關係矩陣df計算方式:在同一個評論中,如果同時出現劉在石和池石鎮,那麼他們的聯繫值+1;再用(劉在石和池石鎮的聯繫值/池石鎮出現在評論的次數)*100得到他們的相關性係數。

foriindf.index:

s=df.loc[i][i]

forjin["池石鎮","劉在石","宋智孝","李光洙","金鐘國","gary","haha","全昭敏","梁世贊"]:

df.loc[i][j]=df.loc[i][j]/s*100

fig=pyl.figure() names=["chishizhen","liuzaishi","songzhixiao","liguangzhu","jinzgongguo","gary","haha","quanshaomin","liangshizan"]

ax=fig.add_subplot(figsize=(100,100))

ax=seaborn.heatmap(df, cmap="rainbow",linewidths =0.05, vmax =100,vmin =,annot =True, annot_kws = {"size":6,"weight":"bold"})

pyl.xticks(np.arange(9) +0.5, names,rotation=-90)

pyl.yticks(np.arange(9) +0.5, names,rotation=360)

ax.set_title("Characteristic correlation")# 標題設置

pyl.show()

社交網路關係網

在社交網路關係網中,按紅、黃、綠、藍將聯繫的緊密程度劃分為四個等級,其中紅色代表聯繫非常緊密,而藍色是不緊密。

可以看到,李光洙、haha、劉在石三人聯繫非常緊密,同時金鐘國和宋智孝的關係也非常密切。對於Gary,自從他退出Running man以後,各成員和他的聯繫都非常小。

def network():

data=pandas.read_csv("run_edge.csv",encoding="utf-8",engine="python")

G = nx.Graph()

pyl.figure(figsize=(20,20))

foriindata.index: G.add_weighted_edges_from([(data.loc[i]["one"],data.loc[i]["two"],data.loc[i]["count"])])

n=nx.draw(G)

pyl.show()

pos=nx.spring_layout(G)

large=[(x,y)for(x,y,z)inG.edges(data=True)ifz["weight"]>100]

middle = [(x, y)for(x, y, z)inG.edges(data=True)if50

middlev = [(x, y)for(x, y, z)inG.edges(data=True)if10

small=[(x,y)for(x,y,z)inG.edges(data=True)ifz["weight"]

nx.draw_networkx_nodes(G,pos,alpha=0.6)

nx.draw_networkx_edges(G,pos,edgelist=large,width=3,edge_color="red")

nx.draw_networkx_edges(G, pos, edgelist=middle, width=2, edge_color="yellow")

nx.draw_networkx_edges(G, pos, edgelist=middlev, width=1, edge_color="yellowgreen")

nx.draw_networkx_edges(G, pos, edgelist=small, width=0.5, edge_color="green")

nx.draw_networkx_labels(G,pos,font_size=10,font_family="simhei")

pyl.axis("off")

pyl.show()

詞雲圖

這個詞雲圖我是用R做的,但是R的詞雲圖背景是要全黑和全白,所以就放棄了給詞雲加個圖案的想法。

回到詞雲圖,可以看出,大家對於節目本身,各位成員的討論是很多的,同時在評論里也表達了自己對Running man各種喜愛之情。

defcomment(com):

df=pandas.DataFrame()

pl=[]

stopword=["的","了","是","。",","," ","?","!","就","
",":","「","」","*","=","(",")","嗎","吧","(",")","?","[","]","、","°","?","!",".","-","`",";",",","《","》"]

foriinrange(len(com)):

cut_list=jieba.cut(com[i],cut_all=False)

w="/".join(cut_list)

w=w.split("/")

forjinw:

ifnotjinstopword:

pl.append(j)

forsinset(pl):

iflen(s)>1:

ifpl.count(s) >50:

x = {}

x["word"]=s.strip("
")

x["count"]=pl.count(s)

df=df.append(x,ignore_index=True)

print(df)

df.to_csv("jieba.csv",encoding="utf-8",index=False,mode="a", header=False)

print(df)

#下面用R生成詞雲圖

library(wordcloud2)

data

jieba.csv")

f=data.frame(data)

f

wordcloud2(f)

最後,希望Running man 給我們帶來越來越多歡樂,收視率越來越好噢。

相關代碼上傳到Github(https://github.com/zuobangbang/running-man--Bilibili)。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 CSDN 的精彩文章:

Go 語言:我那麼值錢,我驕傲了嗎?
放棄培訓班自學編程,9 個月後我成為年薪 6 位數的軟體工程師

TAG:CSDN |