Python爬蟲,最新的B站彈幕和評論爬蟲,你們要的冰冰來啦!

最近
想
爬
下
B
站
的
彈幕
和評
論,發(fā)現(xiàn)網(wǎng)上找到的教程基本都失
效了,畢竟爬蟲和反
爬是
屬
于
魔
高
一
尺、道高一丈的雙方,程序員小哥哥們
在網(wǎng)
絡(luò)的兩端斗智斗勇,也是精彩紛呈。
當(dāng)然了,對于爬蟲這一方,爬取網(wǎng)站數(shù)據(jù),一般目的都是比較明確的,比如我這里就是為了冰冰,廢話不多說,開干!
獲取彈幕數(shù)據(jù)
這里先聲明一點,雖然網(wǎng)絡(luò)上的整體教程都失效了,但是有一些步驟還是可以參考的,比如我們可以知道,對于彈幕數(shù)據(jù),我們是可以通過如下的一個接口來獲取的
?https://comment.bilibili.com/xxxx.xml
在瀏覽器打開可以看到如下:
數(shù)據(jù)還是非常干凈的,那么下一步就是看如何獲取這個 xml 的 url 地址了,也就是如何獲取 324768988 ID
接下來我們搜索整個網(wǎng)頁的源碼,可以發(fā)現(xiàn)如下情況
也就是說,我們需要的 ID 是可以在 script 當(dāng)中獲取的,下面就來編寫一個提取 script 內(nèi)容的函數(shù)
def?getHTML_content(self):
????????#?獲取該視頻網(wǎng)頁的內(nèi)容
????????response?=?requests.get(self.BVurl,?headers?=?self.headers)
????????html_str?=?response.content.decode()
????????html=etree.HTML(html_str)
????????result=etree.tostring(html)
????????return?result
def?get_script_list(self,str):
????html?=?etree.HTML(str)
????script_list?=?html.xpath("http://script/text()")
????return?script_list
拿到所有的 script 內(nèi)容之后,我們再來解析我們需要的數(shù)據(jù)
script_list?=?self.get_script_list(html_content)
#?解析script數(shù)據(jù),獲取cid信息
for?script?in?script_list:
????????if?'[{"cid":'?in?script:
????????????find_script_text?=?script
final_text?=?find_script_text.split('[{"cid":')[1].split(',"page":')[0]
最后,我們再把整體代碼封裝成一個類,就完成了彈幕抓取的數(shù)據(jù)收集工作了
spider?=?BiliSpider("BV16p4y187hc")
spider.run()
結(jié)果如下:
獲取評論數(shù)據(jù)
對于評論數(shù)據(jù),可能要復(fù)雜一些,需要分為主(main)評論和回復(fù)主評論的 reply 評論
我們通過瀏覽器工具抓取網(wǎng)頁上的所有請求,然后搜索 reply,可以得到如下結(jié)果
我們先來看看 main 請求,整理后通過瀏覽器訪問如下
也可以直接通過 requests 請求
通過觀察可以得知,響應(yīng)消息里的 replies 就是主評論內(nèi)容,同時我們還可以改變 url 當(dāng)中的 next 參數(shù)來翻頁,進(jìn)而請求不同的數(shù)據(jù)
這里我們再關(guān)注下 rpid 參數(shù),這個會用于 reply 評論中
再來看看 reply 評論,同樣可以使用 requests 直接訪問,同時 url 當(dāng)中的 root 參數(shù)就是我們上面提到的 rpid 參數(shù)
我們厘清了上面的關(guān)系之后,我們就可以編寫代碼了
def?get_data(data):
????data_list?=?[]
????comment_data_list?=?data["data"]["replies"]
????for?i?in?comment_data_list:
????????data_list.append([i['rpid'],?i['like'],?i['member']['uname'],?i['member']['level_info']['current_level'],?i['content']['message']])
????return?data_list
def?save_data(data_type,?data):
????if?not?os.path.exists(data_type?+?r'_data.csv'):
????????with?open(data_type?+?r"_data.csv",?"a+",?encoding='utf-8')?as?f:
????????????f.write("rpid,點贊數(shù)量,用戶,等級,評論內(nèi)容\n")
????????????for?i?in?data:
????????????????rpid?=?i[0]
????????????????like_count?=?i[1]
????????????????user?=?i[2].replace(',',?',')
????????????????level?=?i[3]
????????????????content?=?i[4].replace(',',?',')
????????????????row?=?'{},{},{},{},{}'.format(rpid,like_count,user,level,content)
????????????????f.write(row)
????????????????f.write('\n')
????else:
????????with?open(data_type?+?r"_data.csv",?"a+",?encoding='utf-8')?as?f:
????????????for?i?in?data:
????????????????rpid?=?i[0]
????????????????like_count?=?i[1]
????????????????user?=?i[2].replace(',',?',')
????????????????level?=?i[3]
????????????????content?=?i[4].replace(',',?',')
????????????????row?=?'{},{},{},{},{}'.format(rpid,like_count,user,level,content)
????????????????f.write(row)
????????????????f.write('\n')
for?i?in?range(1000):
????url?=?"https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next={}&type=1&oid=972516426&mode=3&plat=1&_=1632192192097".format(str(i))
????print(url)
????d?=?requests.get(url)
????data?=?d.json()
????if?not?data['data']['replies']:
????????break
????m_data?=?get_data(data)
????save_data("main",?m_data)
????for?j?in?m_data:
????????reply_url?=?"https://api.bilibili.com/x/v2/reply/reply?jsonp=jsonp&pn=1&type=1&oid=972516426&ps=10&root={}&_=1632192668665".format(str(j[0]))
????????print(reply_url)
????????r?=?requests.get(reply_url)
????????r_data?=?r.json()
????????if?not?r_data['data']['replies']:
????????????break
????????reply_data?=?get_data(r_data)
????????save_data("reply",?reply_data)
????????time.sleep(5)
????time.sleep(5)
爬取過程中:
這樣,針對一個冰冰視頻,我們就完成了上千評論的抓取
下面我們簡單做一些可視化動作
先來看下我們爬取的數(shù)據(jù)整體的樣子
因為數(shù)據(jù)中有一些空值,我們來處理下
df_new?=?df.dropna(axis=0,subset?=?["用戶"])??
下面就可以作圖了,GO!
使用 pyecharts 還是我們的首選,畢竟編寫容易
評論熱度
df1?=?df.sort_values(by="點贊數(shù)量",ascending=False).head(20)
c1?=?(
????Bar()
????.add_xaxis(df1["評論內(nèi)容"].to_list())
????.add_yaxis("點贊數(shù)量",?df1["點贊數(shù)量"].to_list(),?color=Faker.rand_color())
????.set_global_opts(
????????title_opts=opts.TitleOpts(title="評論熱度Top20"),
????????datazoom_opts=[opts.DataZoomOpts(),?opts.DataZoomOpts(type_="inside")],
????)
????.render_notebook()
)

等級分布
pie_data?=?df_new.等級.value_counts().sort_index(ascending=False)
pie_data.tolist()
c2?=?(
????Pie()
????.add(
????????"",
????????[list(z)?for?z?in?zip([str(i)?for?i?in?range(6,?1,?-1)],?pie_data.tolist())],
????????radius=["40%",?"75%"],
????)
????.set_global_opts(
????????title_opts=opts.TitleOpts(title="等級分布"),
????????legend_opts=opts.LegendOpts(orient="vertical",?pos_top="15%",?pos_left="2%"),
????)
????.set_series_opts(label_opts=opts.LabelOpts(formatter=":?{c}"))
????.render_notebook()
)

評論詞云
def?wordcloud(data,?name,?pic=None):
????comment?=?jieba.cut(str(data),?cut_all=False)
????words?=?'?'.join(comment)
????img?=?Image.open(pic)
????img_array?=?np.array(img)
????wc?=?WordCloud(width=2000,?height=1800,?background_color='white',?font_path=font,?mask=img_array,
???????????????????stopwords=STOPWORDS,?contour_width=3,?contour_color='steelblue')
????wc.generate(words)
????wc.to_file(name?+?'.png')
wordcloud(df_new["評論內(nèi)容"],?"冰冰",?'1.PNG')

好了,今天的分享就到這里,喜歡冰冰就點個在看吧
后臺回復(fù)“B站冰冰”獲取完整代碼
![]()
麟哥新書已經(jīng)在當(dāng)當(dāng)上架了,我寫了本書:《拿下Offer-數(shù)據(jù)分析師求職面試指南》,目前當(dāng)當(dāng)正在舉行活動,大家可以用相當(dāng)于原價5折的預(yù)購價格購買,還是非常劃算的 ? ? ? ? ? ? ? ? ? ? ? ? ? ??

數(shù)據(jù)森麟公眾號的交流群已經(jīng)建立,許多小伙伴已經(jīng)加入其中,感謝大家的支持。大家可以在群里交流關(guān)于數(shù)據(jù)分析&數(shù)據(jù)挖掘的相關(guān)內(nèi)容,
還沒有加入的小伙伴可以掃描下方管理員二維碼,進(jìn)群前一定要關(guān)注公眾號奧,關(guān)注后讓管理員幫忙拉進(jìn)群,期待大家的加入。
管理員二維碼:
