【python爬蟲專項(25)】新型冠狀病毒肺炎B站視頻彈幕數據爬並做數據詞雲展示

1、查看要爬取頁面

打開B站網址,輸入“新型冠狀病毒肺炎”關鍵字,顯示界面如下:
在這裏插入圖片描述

2、確定爬蟲邏輯

查看網頁的內容後,一個網址頁面下20個視頻,這裏只採集20頁的視頻數據(共400個視頻),因爲是出現的視頻按照點擊量進行排序的,所以再往後的視頻爬取意義就不大了,因此基本爬蟲邏輯如下:

【分頁網址的url採集】——> 【單個視頻url的採集】——> 【進入視頻播放頁面獲取數據信息】——> 【打開存放彈幕的網頁】 ——> 【按照要求爬取數據並存放到數據庫】

函數式編程:
1)函數式編程
函數1:get_outer_urls(n) → 【分頁網址url採集】
        n:爬取頁數
        結果:得到分頁網址的list

函數2:get_inner_urls(ui,d_h,d_c) → 【視頻頁面url採集】
        ui:分頁網址
        d_h:user-agent信息
        d_c:cookies信息
        結果:得到存放單個視頻頁面的list

函數3:get_data(ui,d_h,d_c,table) → 【視頻頁面數據採集 / cid信息 / 彈幕xml數據採集】
        ui:視頻頁面網址
        d_h:user-agent信息
        d_c:cookies信息
        table:mongo集合對象

3、實戰操作

步驟一、前期準備並封裝第一個函數

1)導入相關的庫,和設置代碼分開標識
在這裏插入圖片描述
2)分析網頁的規律,查看網頁的2-4頁(一般選取2-4就可以看出規律),網址如下:

u2 = https://search.bilibili.com/all?keyword=%E6%96%B0%E5%9E%8B%E5%86%A0%E7%8A%B6%E7%97%85%E6%AF%92%E8%82%BA%E7%82%8E&order=click&duration=0&tids_1=0&page=2
u3 = https://search.bilibili.com/all?keyword=%E6%96%B0%E5%9E%8B%E5%86%A0%E7%8A%B6%E7%97%85%E6%AF%92%E8%82%BA%E7%82%8E&order=click&duration=0&tids_1=0&page=3
u4 = https://search.bilibili.com/all?keyword=%E6%96%B0%E5%9E%8B%E5%86%A0%E7%8A%B6%E7%97%85%E6%AF%92%E8%82%BA%E7%82%8E&order=click&duration=0&tids_1=0&page=4
......

通過2-4頁網址的梳理,可以看出分頁網址的規律,也就是最後面的“page=”之後數字發生變化,而且對應着具體的頁碼,那麼獲取前二十頁的分頁網址,就可以使用下面的方式:

urllist = []
for i in range(1,21):
    ui = f"https://search.bilibili.com/all?keyword=%E6%96%B0%E5%9E%8B%E5%86%A0%E7%8A%B6%E7%97%85%E6%AF%92%E8%82%BA%E7%82%8E&order=click&duration=0&tids_1=0&page={i}"
    urllist.append(ui)
    
print(urllist)

輸出結果爲:(這裏只截取前五頁的網址)
在這裏插入圖片描述
3) 封裝第一個函數

def get_outer_urls(n):
    '''
    【分頁網址url採集】
    n:爬取頁數
    結果:得到分頁網頁的list
    '''
    lst = []
    for i in range(1,21):
        ui = f"https://search.bilibili.com/all?keyword=%E6%96%B0%E5%9E%8B%E5%86%A0%E7%8A%B6%E7%97%85%E6%AF%92%E8%82%BA%E7%82%8E&order=click&duration=0&tids_1=0&page={i}"
        lst.append(ui)
    
    return(lst)

urllst = get_outer_urls(20)
print(urllst)

輸出結果和上面的一致

步驟二、設置請求頭headers和登錄信息cookies

這一步需要用戶登錄,沒有賬號的話,需要進行註冊,cookies和headers(每個人的cookies和headers應單獨設置)的獲取方式如下,

文字詳述: 以上面的登錄後的網頁界面爲例,鼠標右鍵檢查,然後選擇右邊標籤Network,然後刷新一下該網頁,這時候在右方Doc下面的Name菜單欄下會出現一個新的信息,選擇第一個文件,然後拉到底,就可以找到cookies和headers的信息。

步驟歸納:【登錄的頁面】–> 【右鍵檢查】–> 【Network】–> 【刷新】–> 【Doc下面的Name菜單欄】–> 【點擊第一個文件下拉到底】–> 【Request Headers下】

圖示
在這裏插入圖片描述
查找到headers和cookies之後,將其寫入到字典中儲存,如下(代碼在spyder裏運行)

dic_headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"}

cookies = "_uuid=3D3C1683-5F16-D3EC-36E2-5967E731F7DA81323infoc; buvid3=3EB2F2F9-8EE3-4AFE-B3D6-7620A3B2E636155823infoc; LIVE_BUVID=AUTO4015671567822432; sid=bj42fy4m; CURRENT_FNVAL=16; stardustvideo=1; rpdid=|(umYuYRkm~|0J'ulY~ul~JlY; UM_distinctid=16ce1f17c989db-0c9243ec350826-e343166-144000-16ce1f17c99a18; CURRENT_QUALITY=0; DedeUserID=38449436; DedeUserID__ckMd5=272068a4511232d7; SESSDATA=3a11597f%2C1583975698%2C7bfdfc21; bili_jct=d8d63e8aa5a2eb9adf9f30698873d271; INTVER=1; arrange=matrix"
dic_cookies = {}
for i in cookies.split("; "):
	dic_cookies[i.split("=")[0]] = i.split("=")[1]

print(dic_headers)
print(dic_cookies)

輸出結果如下:
在這裏插入圖片描述

步驟三、網頁信息請求和網頁初解析

首先嚐試進行網頁信息請求(以搜索關鍵詞顯示的第一個網頁爲例),代碼如下

url = 'https://search.bilibili.com/all?keyword=%E6%96%B0%E5%9E%8B%E5%86%A0%E7%8A%B6%E7%97%85%E6%AF%92%E8%82%BA%E7%82%8E&order=click&duration=0&tids_1=0'
r = requests.get(url,headers = dic_headers, cookies = dic_cookies)
print(r)

輸出結果爲:<Response [200]> (說明網站信息可以正常訪問,接下來進行頁面的解析)

在網頁界面鼠標右鍵,選擇檢查,可以發現,搜到的視頻都是在【ul】標籤下的【li】標籤裏面,如下
在這裏插入圖片描述
那麼代碼實現視頻信息的獲取如下:

soup = BeautifulSoup(r.text, 'lxml')
lis = soup.find("ul",class_ = "video-list clearfix").find_all("li")
print(lis[0])

輸出的結果爲:(這裏以第一個視頻爲例,輸出結果)
在這裏插入圖片描述
接着就可以獲取視頻的url、標題、上傳時間和作者信息等數據,但是由於彈幕信息必須要進入視頻的播放界面纔可以獲取到,因此在這一步只需要獲取視頻url即可,其餘的信息在視頻播放界面的網頁上獲取,通過上面的輸出可以發現,視頻網址放在裏【a】標籤下
在這裏插入圖片描述
代碼實現視頻url的獲取如下:

inner_url = lis[0].a['href']
print(inner_url)

輸出的結果爲:(發現最前面少了https:,在封裝函數的時候需要加上)
‘//www.bilibili.com/video/av84850049?from=search’

步驟四、封裝第二個函數

上面實現了單個視頻url的獲取,接下來只需要進行遍歷循環並把結果儲存到列表即可,也就是封裝第二個函數的要求,代碼如下

def get_inter_urls(ui,d_h,d_c):
    '''
    【視頻頁面url採集】
    ui:視頻信息網頁url
    d_h:user-agent信息
    d_c:cookies信息
    結果:得到一個視頻頁面的list
    '''
    ri = requests.get(ui, headers = d_h, cookies = d_c)
    soupi = BeautifulSoup(ri.text, 'lxml')
    lis = soupi.find('ul',class_="video-list clearfix").find_all('li')
    lst = []
    for li in lis:
        lst.append('https:' + li.a['href'])
    return lst

url_1 = urllst[0]
print(get_inter_urls(url_1,dic_headers,dic_cookies))

輸出結果爲:(以第一頁爲例,可以輸出該頁的20個視頻的url)
在這裏插入圖片描述

步驟五、網頁深度解析(獲取標題、時間和彈幕等)並將數據存入數據庫

1) 獲取標題
和之前的網頁初解析一樣,找到標題所對應的的標籤信息,如下
在這裏插入圖片描述
代碼實現如下:

url_1 = urllst[0]
inner_lst = get_inter_urls(url_1,dic_headers,dic_cookies)

r = requests.get(inner_lst[0],headers = dic_headers, cookies = dic_cookies)
soup = BeautifulSoup(r.text, 'lxml')
title = soup.h1['title']
print(title)

輸出結果如下:
在這裏插入圖片描述
2) 獲取上傳時間
上傳時間所對應的標籤信息如下,信息在【div class=‘video-data’】標籤下的【span】裏面
在這裏插入圖片描述
代碼實現如下:

upload_time = soup.find("span", class_ = "a-crumbs").next_sibling.text
print(upload_time)

輸出的結果爲:
在這裏插入圖片描述
3) 獲取作者
作者對應的標籤信息如下,名稱在【div class=‘name’】下的第一個【a】標籤下
在這裏插入圖片描述
代碼實現如下:

author = soup.find("div", class_ = 'name').a.text
print(author)

輸出的結果爲:
在這裏插入圖片描述
4) 獲取彈幕數據
① 解析一下cid
首先要從 B 站彈幕的說起,B 站視頻的 ID 名字是 cid,一個 AV (視頻)號下如果有多個分 P,就會佔用多個 cid,cid 可以看做是視頻的唯一 ID,通過這個 ID ,我們可以讀取到 B 站的彈幕格式爲 comment.bilibili.com/[cid].xml,在一開始給出的彈幕網址就爲:https://comment.bilibili.com/84682646.xml

比如在第一個視頻的網頁界面點擊鼠標右鍵查看源代碼,然後搜索“cid”,就會發現相關的信息
在這裏插入圖片描述
複製"cid":後的數字查看一下這個信息在“檢查”界面對應的標籤的信息是怎麼樣的,搜索如下,可以看出都是在【script】標籤下面
在這裏插入圖片描述
② cid 數據採集
對比“源代碼"和"檢查"頁面,發現可以很好的獲取cid的方式是通過在源代碼窗口下查找,因爲這裏面的數據直接以字典的形式存儲的,而如果再"檢查"界面進行匹配標籤,在來查找內容就顯着很複雜,代碼如下

cid = re.search(r'"cid":(\d*),', ri.text).group(1)
print(cid)

輸出的結果爲:
在這裏插入圖片描述
③ 彈幕信息採集
這裏只需要將對應位置的數字換成cid信息即可,然後嘗試獲取該cid對應的url下面的內容(注意亂碼的解決方式)

cid = re.search(r'"cid":(\d*),', r.text).group(1)
cid_url = f"https://comment.bilibili.com/{cid}.xml"
r2 = requests.get(cid_url)
r2.encoding = r2.apparent_encoding
soup2 = BeautifulSoup(r2.text, 'lxml')
print(soup2)

輸出結果爲:(截取部分片段)
在這裏插入圖片描述
檢驗能否獲取該頁面正常數據

dmlst = re.findall(r'<d.*?/d>',r2.text)
print(dmlst)

輸出的結果爲:(截取部分片段)
在這裏插入圖片描述
彈幕的標籤信息全部存儲到了dmlst裏面了,接下來是提取裏面的內容,順便把之前的內容也寫入到字典裏面

for dm in dmlst:
    dic = {}
    dic['標題'] = title
    dic['上傳時間'] = upload_time
    dic['cid'] = cid
    dic['作者'] = author
    dic['彈幕內容'] = re.search(r'>(.*)<',dm).group(1)
    dic['其他信息'] = re.search(r'p="(.*)">',dm).group(1)
    print(dic)

輸出結果爲:(截取部分)
在這裏插入圖片描述
至此,就把相應的數據全部儲存在字典裏面了,接下來就是配置數據庫和封裝第三個函數了

步驟六、配置數據庫和封裝第三個函數

1) 配置數據庫

import pymongo
myclient = myclient = pymongo.MongoClient("mongodb://localhost:27017/")
db = myclient['冠狀病毒彈幕數據']
datatable = db['data']

上述代碼實現數據庫的創建及命名,以及存放數據表格的創建

2)封裝第三個函數,並將數據寫入到數據庫

只需要將每次生成的dic直接插入到創建的數據表格中即可,爲了可視化儲存過程,可以進行計數統計

def get_data(ui,d_h,d_c,table):
    '''
    ui:視頻頁面網址
    d_h:user-agent信息
    d_c:cookies信息
    table:mongo集合對象
    '''
    ri = requests.get(url = ui, headers = d_h, cookies = d_c)
    soupi = BeautifulSoup(ri.text, 'lxml')
    #title = soupi.find(id = "viewbox_report").span.text
    title = soupi.h1['title']
    upload_time = soupi.find("span", class_ = "a-crumbs").next_sibling.text
    #upload_time = re.search(r'(20.*\d)',soupi.find("div",class_ ="video-data").text)
    cid = re.search(r'"cid":(\d*),', ri.text).group(1)
    cid_url = f"https://comment.bilibili.com/{cid}.xml"
    r2 = requests.get(cid_url)
    r2.encoding = r2.apparent_encoding
    dmlst = re.findall(r'<d.*?/d>',r2.text)
    
    n = 0
    for dm in dmlst:
        dic = {}
        dic['標題'] = title
        dic['上傳時間'] = upload_time
        dic['cid'] = cid
        dic['作者'] = author
        dic['彈幕內容'] = re.search(r'>(.*)<',dm).group(1)
        dic['其他信息'] = re.search(r'p="(.*)">',dm).group(1)
        table.insert_one(dic)
        n += 1 
    return n 

最後運行代碼:

inner_urllst = []
    error_lst = []
    for outer_url in urllst:
        try:
            inner_urllst.extend(get_inter_urls(outer_url,dic_headers,dic_cookies))
            print("已成功獲取{}條視頻數據".format(len(inner_urllst)))
        except:
            error_lst.append(outer_url)
            print("獲取視頻信息失敗,網址爲:",outer_url)
                    
    
    count = 0
    for u in inner_urllst:
        try:
            count += get_data(u,dic_headers,dic_cookies,datatable)
            print('數據採集並存入成功,總共採集{}條數據'.format(count))
        except:
            error_lst.append(u)
            print('數據採集失敗,數據網址爲:',u)	

輸出的結果爲:
在這裏插入圖片描述
數據庫裏面的數據
在這裏插入圖片描述

數據分析

首先將保存在MongoDB數據庫的數據導出,如下
在這裏插入圖片描述
接着就可以就可以讀取桌面的csv文件了,代碼如下:

import pandas as pd
    
df = pd.read_csv(r"C:\Users\86177\Desktop\result.csv")
data = df['彈幕內容']
data.value_counts()[:20]

輸出的結果爲:(按照字頻選擇前二十進行輸出)
在這裏插入圖片描述
最後將結果進行詞雲展示;

import pandas as pd
from wordcloud import WordCloud
    
df = pd.read_csv(r"C:\Users\86177\Desktop\result.csv")
data = df['彈幕內容']
txt = " ".join(data.tolist())
txt = txt.replace("哈","")
wc = WordCloud(width=600, height=400).generate(txt)
wc.to_file('wordcloud.png')

輸出的結果爲:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章