爬取B站視訊播放量及資料視覺化
爬取B站視訊播放量及資料視覺化
1.爬取資料
分析要爬取的每個欄位的如下
'region': [視訊分割槽],'title': [視訊標題], 'view_num': [播放量], 'danmu': [彈幕], 'upload_time': [上傳時間], 'up_author': [作者], 'video_url': [視訊連結]
程式碼如下
#-*- codeing = utf-8 -*-
#@Time : 2020/12/1 18:36
#@Author : 招財進寶
#@File : spiderW.py
#@Software: PyCharm
import requests
from lxml import etree
import time
import random
import csv
import pandas as pd
def get_target(keyword, page,saveName):
result = pd.DataFrame()
for i in range(1, page + 1):
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'}
url = 'https://search.bilibili.com/all?keyword={}&from_source=nav_suggest_new0&page={}'.format(keyword, i)
html = requests.get(url.format(i), headers=headers)
bs = etree.HTML(html.text)
items = bs.xpath('//li[@class = "video-item matrix"]')
for item in items:
video_url = item.xpath('div[@class = "info"]/div/a/@href')[0].replace("//","") #每個視訊的來源地址
title = item.xpath('div[@class = "info"]/div/a/@title')[0] #每個視訊的標題
region = item.xpath('div[@class = "info"]/div[1]/span[1]/text()')[0].strip('\n ') #每個視訊的分類版塊如動畫
view_num = item.xpath('div[@class = "info"]/div[3]/span[1]/text()')[0].strip('\n ') #每個視訊的播放量
danmu = item.xpath('div[@class = "info"]/div[3]/span[2]/text()')[0].strip('\n ') #彈幕
upload_time = item.xpath('div[@class = "info"]/div[3]/span[3]/text()')[0].strip('\n ') # 上傳日期
up_author = item.xpath('div[@class = "info"]/div[3]/span[4]/a/text()')[0].strip('\n ') #up主
df = pd.DataFrame({'region': [region],'title': [title], 'view_num': [view_num], 'danmu': [danmu], 'upload_time': [upload_time], 'up_author': [up_author], 'video_url': [video_url]})
result = pd.concat([result, df])
time.sleep(random.random() + 1)
print('已經完成b站第 {} 頁爬取'.format(i))
saveName = saveName + ".csv"
result.to_csv(saveName, encoding='utf-8-sig',index=False) # 儲存為csv格式的檔案
return result
if __name__ == "__main__":
keyword = input("請輸入要搜尋的關鍵詞:")
page = int(input("請輸入要爬取的頁數:"))
saveName = input("請輸入要儲存的檔名:")
get_target(keyword, page,saveName)
執行
執行時可輸入要爬取的視訊關鍵詞及爬取頁數等內容,如下,本人進行爬取B站王冰冰的相關內容
執行結果
2.資料分析
參考連結:
https://blog.csdn.net/yoggieCDA/article/details/109448088
https://blog.csdn.net/weixin_44953364/article/details/93981915
2.1讀取資料
#-*- codeing = utf-8 -*-
#@Time : 2020/12/2 9:07
#@Author : 招財進寶
#@File : dataAnalyse.py
#@Software: PyCharm
#此處使用的pyecharts包是1版本的,注意0版本與1版本不相容
#1.讀入資料
import pandas as pd
#設定顯示的最大列、寬等引數,消掉列印不完全中間的省略號
pd.set_option('display.max_columns', None)
pd.set_option('display.width', None)
pd.set_option('display.max_colwidth', 1000)
df = pd.read_csv('wangBB.csv',header=0,encoding="utf-8-sig")
# print(df.shape) #資料大小(行、列)
# print(df.head()) #資料內容,只列印了頭部的前4個資訊
當資料讀入時,列印頭部的資訊如下所示
2.2資料預處理
此部分我們初步對原始資料進行處理,其中包含:
- 去除重複值
- view_num和danmu:單位轉換
- 篩選資料
程式碼如下
#2.資料預處理
import numpy as np
def transform_unit(x_col):
"""
功能:轉換數值型變數的單位
"""
# 提取數值
s_num = df[x_col].str.extract('(\d+\.*\d*)').astype('float')
# 提取單位
s_unit = df[x_col].str.extract('([\u4e00-\u9fa5]+)')
s_unit = s_unit.replace('萬', 10000).replace(np.nan, 1)
s_multiply = s_num * s_unit
return s_multiply
# 去重
df = df.drop_duplicates()
# 刪除列
df.drop('video_url', axis=1, inplace=True)
# 轉換單位
df['view_num'] = transform_unit(x_col='view_num')
df['danmu'] = transform_unit(x_col='danmu')
# 篩選時間
df = df[(df['upload_time'] >= '2020-09-01') & (df['title'].astype('str').str.contains('王冰冰'))]
#print(df.head())
資料預處理後的資訊如下所示
2.3資料視覺化
需要引入的包
#3.資料視覺化
#注意:此處的pandas版本是最新的1.9.0版本,1版本與0版本是不相容的
import jieba
from pyecharts.charts import Bar, Line, Pie, Map, Scatter, Page #引入柱狀圖、折線圖、餅狀圖、地圖
from pyecharts import options as opts
(1)釋出數量及播放數量折線圖
#釋出熱度
time_num = df.upload_time.value_counts().sort_index() #time_num中包含的是日期,及每個日期內有多少個視訊釋出
print(time_num)
#print(time_num.index)
#某天的播放量(https://www.cnblogs.com/zhoudayang/p/5534593.html)
time_view = df.groupby(by=['upload_time'])['view_num'].sum() #如果需要按照列A進行分組,將同一組的列B求和
print(time_view)
# 折線圖(不同的圖的疊加https://[pyecharts學習筆記]——Grid並行多圖、組合圖、多 X/Y 軸)
line1 = Line(init_opts=opts.InitOpts(width='1350px', height='750px',background_color='white'))
line1.add_xaxis(time_num.index.tolist())
line1.add_yaxis('釋出數量', time_num.values.tolist(),
markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_='min'), #標記最小點及最大點
opts.MarkPointItem(type_='max')]),
# 新增第一個軸,索引為0,(預設也是0)
yaxis_index = 0,
#color = "#d14a61", # 系列 label 顏色,紅色
)
line1.add_yaxis('播放總量', time_view.values.tolist(),
markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_='min'),
opts.MarkPointItem(type_='max')]),
yaxis_index=1, # 上面的折線圖圖預設索引為0,這裡設定折線圖y 軸索引為1
#color="#5793f3", # 系列 label 顏色藍色
)
#新加入一個y軸(索引值是1)下方是對其的詳細配置
line1.extend_axis(
yaxis=opts.AxisOpts(
name="播放總量", # 座標軸名稱
type_="value", # 座標軸型別 'value': 數值軸,適用於連續資料。
min_=0, # 座標軸刻度最小值
max_=int(time_view.max()), # 座標軸刻度最大值
position="right", # 軸的位置 側
# 軸線配置
# axisline_opts=opts.AxisLineOpts(
# # 軸線顏色(預設黑色)
# linestyle_opts=opts.LineStyleOpts(color="#5793f3")
# ),
# 軸標籤顯示格式
#axislabel_opts=opts.LabelOpts(formatter="{value} c"),
)
)
#全域性配置(全域性配置中預設已經存在一個y軸了(預設索引值是0),要想更改此左側的y軸必須更改此處的)
line1.set_global_opts(
yaxis_opts=opts.AxisOpts(
name="釋出數量",
min_=0,
max_=int(time_num.max()),
position="left",
#offset=80, # Y 軸相對於預設位置的偏移,在相同的 position 上有多個 Y 軸的時候有用。
#軸線顏色
axisline_opts=opts.AxisLineOpts(
linestyle_opts=opts.LineStyleOpts(color="#d14a61")
),
axislabel_opts=opts.LabelOpts(formatter="{value} ml"),
),
title_opts=opts.TitleOpts(title='王冰冰視訊釋出熱度/播放熱度走勢圖', pos_left='5%'),#標題
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate='45')), #x軸的標籤傾斜度為垂直
)
#系列配置項,不顯示標籤(不會將折線上的每個點的值都在圖中顯示出來)
line1.set_series_opts(linestyle_opts=opts.LineStyleOpts(width=3),
label_opts=opts.LabelOpts(is_show=False)
)
line1.render("line.html")
執行成功後會在當前目錄生成一個html檔案,使用瀏覽器開啟,就能看到生成的直線圖,也可以在瀏覽器右擊生成圖片
(2)不同分割槽的視訊釋出數量所佔百分比,環形圖
#(2)不同分割槽的視訊釋出數量,環形圖,所佔百分比(https://blog.csdn.net/vv_eve/article/details/107991704)
#對某一列相同的類別合併,每個類別出現的頻次
region_num = df.region.value_counts().sort_index() #region_num中包含的是分割槽,每個分割槽有多少個視訊
#print(region_num.head())
#print(type(region_num))
#提取某一列的資料,.values作用是將矩陣轉為ndarray型,為了畫圖時傳入引數矩陣
columns = region_num.index.tolist() #所有的第一列的值,變為列表(各個分割槽)
#print(columns)
data = region_num.values.tolist() #所有的第2列的值,變為列表(每個分割槽的視訊釋出數)
#print(data)
#設定餅形圖(https://blog.csdn.net/vv_eve/article/details/107991704)
pie = Pie()
pie.add("",
[list(z) for z in zip(columns, data)],
radius=["40%", "55%"], #餅形圖大小
center=["35%", "50%"],# 位置設定
label_opts=opts.LabelOpts(
position="outside",
formatter="{a|{a}}{abg|}\n{hr|}\n {b|{b}: }{c} {per|{d}%} ",
background_color="#eee",
border_color="#aaa",
border_width=1,
border_radius=4,
rich={
"a": {"color": "#999", "lineHeight": 22, "align": "center"},
"abg": {
"backgroundColor": "#e3e3e3", #上面的背景設定
"width": "100%",
"align": "right",
"height": 22,
"borderRadius": [4, 4, 0, 0],
},
"hr": { #相當於中間的分割線樣式設定
"borderColor": "#aaa",
"width": "100%",
"borderWidth": 0.5,
"height": 0,
},
"b": {"fontSize": 16, "lineHeight": 33},#名稱文字樣式
"per": { # 百分數的字型樣式設定
"color": "#eee",
"backgroundColor": "#334455",
"padding": [2, 4], #[高,寬]設定,那個背景矩形
"borderRadius": 2, #圓角設定
},
},
),
)
pie.set_global_opts(
title_opts=opts.TitleOpts(title="B站各視訊分割槽釋出數量"),
legend_opts=opts.LegendOpts(pos_left="65%",
orient="vertical"
),
)
#進行系列的設定,此處的設定會覆蓋前面add()中的formatter設定,功能是相同的
pie.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {d}%")) #此處{b}表示顯示數值項名稱,{d}表示數值項所佔百分比
pie.render("pie.html")
當系列設定標籤的結果為pie.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))
環形圖如下:
解決上方不顯示百分比的問題https://github.com/pyecharts/pyecharts/issues/523
當系列設定的標籤如下,會覆蓋add()中的標籤的設定
pie.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {d}%"))
(3)不同分割槽的視訊播放總量,柱形圖
#(3)不同分割槽的視訊播放總量,設定柱形圖
#某分割槽的播放總量(https://www.cnblogs.com/zhoudayang/p/5534593.html)
region_view = df.groupby(by=['region'])['view_num'].sum() #如果需要按照列A進行分組,將同一組的列B求和
region_view =region_view.sort_values() #將第2列及values列進行排序,預設小的在前,大的在後
#print(region_view)
columns = region_view.index.tolist() #所有的第一列的值,變為列表(各個分割槽)
#print(columns)
data = region_view.values.tolist() #所有的第2列的值,變為列表(每個分割槽的視訊播放總量)
#print(data)
# 條形圖(引入的Bar包)
#另外一種寫法
bar = (
Bar(init_opts=opts.InitOpts(width='1350px', height='750px'))
.add_xaxis(columns)
.add_yaxis("播放量", data,
markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_='min'), #標註最大最小值
opts.MarkPointItem(type_='max')]),
)
.set_global_opts(title_opts=opts.TitleOpts(title="B站各視訊分割槽播放總量"),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate='45')), # x軸的標籤傾斜度為垂直
)
#系列配置項,不顯示標籤(不會將折線上的每個點的值都在圖中顯示出來)
.set_series_opts( label_opts=opts.LabelOpts(is_show=False) )
)
bar.render("bar.html")
柱狀圖如下:
(4)B站播放數量最高的前10個視訊(x軸和y軸進行交換)
#(4)B站播放數量最高的前10個視訊(x軸和y軸進行交換)
#進行排序(https://blog.csdn.net/happy5205205/article/details/105124051/)
top_num = df.sort_values(by='view_num',ascending=False) #根據列view_num的值進行排序,並按照降序排列(預設是升序)
print(top_num.head(10)) #列印前十個值,降序的
top10_num=top_num.head(10).sort_values(by='view_num') #將前10個拿出來再按照升序排列,因為後面進行條形圖排列,xy軸互換時會將數最大的排在前面
print(top10_num) #列印前十個值,升序的
columns = top10_num.reset_index()['title'].values.tolist() #將某一列的值拿出來做為一個列表
print(columns)
data = top10_num.reset_index()['view_num'].values.tolist() #將某一列的值拿出來做為一個列表
print(data)
#xy互換的條形圖(https://blog.csdn.net/zc666ying/article/details/105095620解決顯示文字不全)
#文字換行顯示(https://www.bbsmax.com/A/q4zVe4A7dK/)
#文字換行顯示https://blog.csdn.net/weixin_43982422/article/details/109315338(自己並未實現)
bar2 = (
Bar(init_opts=opts.InitOpts(width="2000px",height="700px")) #此處通過擴大寬度,來將左側的標題囊括過來
.add_xaxis(columns)
.add_yaxis("播放量", data,
# markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_='min'), #標註最大最小值
# opts.MarkPointItem(type_='max')]),
)
.reversal_axis() #此處將x軸與y軸進行互換
.set_global_opts(
title_opts=opts.TitleOpts(title="B站王冰冰播放數量Top10視訊",pos_left='9%'),
#xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate='45')), # x軸的標籤傾斜度為垂直
#yaxis_opts=opts.AxisOpts(axislabel_opts={"interval":"0"}) #0強制顯示所有標籤
)
#系列配置項,將標籤位置顯示在右側
.set_series_opts( label_opts=opts.LabelOpts(position="right"))
)
bar2.render("bar2.html")
橫向柱狀圖如下:
3.彈幕詞雲分析
參考連結:https://blog.csdn.net/zhuxiao5/article/details/102618211
3.1對排名第一的視訊的彈幕進行詞雲分析
B站的彈幕資料是有介面的,比如說:
https://comment.bilibili.com/********.xml
它以一個固定的url地址+視訊的cid+.xml組成。只要找到你想要的視訊cid,替換這個url就可以爬取所有彈幕了。
找到cid:237910972
通過cid進行彈幕分析
3.2 爬取對應彈幕
#-*- codeing = utf-8 -*-
#@Time : 2020/12/3 16:39
#@Author : 招財進寶
#@File : ciYun.py
#@Software: PyCharm
from bs4 import BeautifulSoup
import pandas as pd
import requests
#爬取對應視訊的彈幕
url = 'http://comment.bilibili.com/251815340.xml' # url連結
html = requests.get(url) # 用於解析
html.encoding = 'utf8' # 編碼格式為utf8
soup = BeautifulSoup(html.text, 'lxml') # 使用bs進行xml的解析
results = soup.find_all('d') # 進行標籤《d》的篩選
comments = [comment.text for comment in results]
print(comments)
comments_dict = {'comments': comments} # 定義一個字典
df = pd.DataFrame(comments_dict)
df.to_csv('bili_danmu2.csv', encoding='utf-8-sig') # 儲存為csv格式的檔案
3.3 生成詞雲
#-*- codeing = utf-8 -*-
#@Time : 2020/12/3 16:50
#@Author : 招財進寶
#@File : ciYun.py
#@Software: PyCharm
#讀取資料
import pandas as pd
data = pd.read_csv('bili_danmu2.csv',header=0,encoding="utf-8-sig")
print(data.shape[0]) #數量
print(data.head()) #資料內容,只列印了頭部的前4個資訊
#詞雲的視覺化(改變詞雲顏色https://blog.csdn.net/qq_43328313/article/details/106824685)
import jieba #分詞(將一個句子分成很多個詞語)
from matplotlib import pyplot as plt #繪圖,資料視覺化,點狀圖、柱狀圖等科學繪圖,和echarts不同,不是直接用於網站,而是生成圖片
from wordcloud import WordCloud #詞雲,形成有遮罩效果的
from PIL import Image #用來做影像處理的(官方預設)
import numpy as np #矩陣運算
#分詞
#詞雲是按照詞來進行統計的,這個使用jieba自動進行詞頻統計
text = ''.join(data['comments']) #此處將所有的評論進行了整合連成一個字串
print(text)
#cut = jieba.cut(text) #將一個字串進行分割
words = list(jieba.cut(text))
ex_sw_words = []
#下方是對目前的一些字串進行篩選,將一些沒有意義的詞語進行清除
stop_words = [x.strip() for x in open('stopwords.txt', encoding="utf-8")]
for word in words:
if len(word) > 1 and (word not in stop_words):
ex_sw_words.append(word)
#print(ex_sw_words)
#print(cut) #返回cut是一個物件<generator object Tokenizer.cut at 0x000002644AAECF48>
string = ' '.join(ex_sw_words) #此處將其物件cut變成字串,可在下方顯示,#' '.join(cut) 以指定字串空格‘ ’作為分隔符,將 cut 中所有的元素(的字串表示)合併為一個新的字串
print(string) #此時可以列印如下
print(len(string)) #個詞,要對這些詞進行統計
#可以自己找圖建議輪廓清晰
img = Image.open(r'aixin.png') #開啟遮罩圖片
img_arry = np.array(img) #將圖片轉換為陣列,有了陣列即可做詞雲的封裝了
from matplotlib import colors
#建立顏色陣列,可更改顏色
color_list=['#CD853F','#DC143C','#00FF7F','#FF6347','#8B008B','#00FFFF','#0000FF','#8B0000','#FF8C00',
'#1E90FF','#00FF00','#FFD700','#008080','#008B8B','#8A2BE2','#228B22','#FA8072','#808080']
#呼叫
colormap=colors.ListedColormap(color_list)
wc = WordCloud(
background_color='white', #背景必須是白色
mask = img_arry, #傳入遮罩的圖片,必須是陣列
font_path = "STXINGKA.TTF", #設定字型,(字型如何找,可以在C:/windows/Fonts中找到名字)
colormap=colormap, # 設定文字顏色
max_font_size=150, # 設定字型最大值
random_state=18 # 設定有多少種隨機生成狀態,即有多少種配色方案
)
#
wc.generate_from_text(string) #從哪個文字生成wc,這個文字必須是切好的詞
#繪製圖片
fig = plt.figure(1) #1表示第一個位置繪製
plt.imshow(wc) #按照wc詞雲的規格顯示
plt.axis('off') #是否顯示座標軸,不顯示(單一圖片)
#plt.show() #顯示生成的詞雲圖片
plt.savefig(r'danmu2.jpg',dpi=400) #輸出詞雲圖片到檔案,預設清晰度是400,這裡設定500可能有點高,注意此處要儲存,show()方法就得註釋
遮罩圖片aixin.png(背景必須是純白的,可以使用摳圖等工具)
生成的詞雲圖片
相關文章
- Python爬取股票資訊,並實現視覺化資料Python視覺化
- 多執行緒爬取B站視訊執行緒
- Golang 爬蟲快速入門 | 獲取 B 站全站的視訊資料Golang爬蟲
- Scrapy爬取二手房資訊+視覺化資料分析視覺化
- 【python】爬取疫情資料並進行視覺化Python視覺化
- Python爬蟲之小說資訊爬取與資料視覺化分析Python爬蟲視覺化
- 最新Python爬蟲和資料視覺化Python爬蟲視覺化
- 【玩具】獲取B站視訊的音訊片段音訊
- python爬蟲練習--爬取虎牙主播原畫視訊Python爬蟲
- Python資料爬取處理視覺化,手把手全流程教學Python視覺化
- Python爬蟲訓練:爬取酷燃網視訊資料Python爬蟲
- 資料視覺化基本原理——視覺化模型視覺化模型
- 資料視覺化【十五】視覺化
- 資料看板視覺化視覺化
- Matlab資料視覺化Matlab視覺化
- 前程無憂崗位資料爬取+Tableau視覺化分析視覺化
- 資料視覺化效果怎麼做,資訊視覺化設計用什麼軟體視覺化
- 視覺化之資料視覺化最強工具推薦視覺化
- 什麼是資料視覺化,為什麼資料視覺化很重要?視覺化
- 資料視覺化--實驗五:高維非空間資料視覺化視覺化
- 奧威BI資料視覺化:讓各層級管理快速獲取資訊視覺化
- 資料視覺化實踐視覺化
- python資料視覺化——echartsPython視覺化Echarts
- 如何看待資料視覺化?視覺化
- 視覺化中的資料視覺化
- python 資料視覺化利器Python視覺化
- 資料視覺化的秘密視覺化
- 【matplotlib教程】資料視覺化視覺化
- 資料視覺化的作用視覺化
- 什麼是資料視覺化?hightopo資料視覺化助力企業數字化視覺化
- 資料視覺化的基本原理——視覺通道視覺化
- 音訊錄製及視覺化處理音訊視覺化
- 智慧公安視覺化資訊研判大資料平臺視覺化大資料
- FFCreator -- 用 node.js 來製作資料視覺化視訊吧Node.js視覺化
- 資料視覺化如何選擇合適的視覺化圖表?視覺化
- 獲獎的資料視覺化示例 讓人視覺震撼視覺化
- (在模仿中精進資料視覺化03)OD資料的特殊視覺化方式視覺化
- 資料視覺化能否代替資料分析視覺化