Python知識(shí)分享網(wǎng) - 專業(yè)的Python學(xué)習(xí)網(wǎng)站 學(xué)Python,上Python222
使用Python做簡(jiǎn)易爬蟲爬取B站評(píng)論
發(fā)布于:2023-07-21 14:59:17

一、前言


        B站評(píng)論沒(méi)有查找功能,就隨手寫了一個(gè)爬蟲爬取B站評(píng)論存儲(chǔ)到本地txt中

        首先需要安裝python的request庫(kù),和beautifulsoup庫(kù)

pip install requests

pip install bs4

        出現(xiàn)successfully就代表安裝成功了

        下面就是所需的所有庫(kù)

 

import requests
from bs4 import BeautifulSoup
import re
import json
from pprint import pprint
import time

 

二、分析網(wǎng)頁(yè)
        

        我們?cè)陧?yè)面中查看源代碼,發(fā)現(xiàn)源代碼中并沒(méi)有有關(guān)評(píng)論的信息。我們繼續(xù)往下滑到評(píng)論的位置,發(fā)現(xiàn)評(píng)論是需要加載一會(huì)才出現(xiàn),這時(shí)候我就猜測(cè)需要抓包才能獲取到評(píng)論的信息。

        打開F12,在network中查詢r(jià)eply有關(guān)選項(xiàng),查找到了評(píng)論信息。
 

使用Python做簡(jiǎn)易爬蟲爬取B站評(píng)論 圖1

 

我提取出URL,查看里面的各項(xiàng)數(shù)據(jù)

使用Python做簡(jiǎn)易爬蟲爬取B站評(píng)論 圖2

     不知道為什么這里的URL需要?jiǎng)h除掉Callback后面的數(shù)據(jù)才能正常查看

         在Edge里下載Json Formatter可以更好的查看。

 

使用Python做簡(jiǎn)易爬蟲爬取B站評(píng)論 圖3

 

發(fā)現(xiàn)一個(gè)包并不能顯示所有的評(píng)論,我們繼續(xù)往下滑,在F12尋找有關(guān)reply的數(shù)據(jù),提取出URL

使用Python做簡(jiǎn)易爬蟲爬取B站評(píng)論 圖4

 

發(fā)現(xiàn)只有next會(huì)改變,那么next=1是什么?實(shí)踐發(fā)現(xiàn)next=1和next=0的數(shù)據(jù)一樣,所以我們編程序的時(shí)候可以直接從1開始。

        但是我們又發(fā)現(xiàn)這里面只有根評(píng)論沒(méi)有子評(píng)論,懷疑子評(píng)論在另一個(gè)包中,查看其中一個(gè)評(píng)論的子評(píng)論,我們又在F12中抓到了一個(gè)新包。

使用Python做簡(jiǎn)易爬蟲爬取B站評(píng)論 圖5

 同樣我們提取URL,觀察replies就是所需要的子評(píng)論。同樣一頁(yè)也不能顯示完所有回復(fù),觀察后發(fā)現(xiàn),各個(gè)評(píng)論只有pn不一樣。

使用Python做簡(jiǎn)易爬蟲爬取B站評(píng)論  圖6

 

那么子評(píng)論和根評(píng)論是怎么聯(lián)系在一起的呢?

        觀察URL,發(fā)現(xiàn)子評(píng)論的URL有root這項(xiàng),我們就去研究了根和子的一致,發(fā)現(xiàn)根的rpid就是子的root,這樣我們就找到了關(guān)系。

使用Python做簡(jiǎn)易爬蟲爬取B站評(píng)論  圖7

 最后在寫代碼的時(shí)候還發(fā)現(xiàn)有個(gè)問(wèn)題,就是有些根評(píng)論不需要展開,那么子評(píng)論的包中replies這一項(xiàng)就是空的,而這些評(píng)論的信息存在梗評(píng)論的包中,我們只需要簡(jiǎn)單判斷一下就可以了。

        了解完結(jié)構(gòu)后,編程就簡(jiǎn)單多了。

 

三、代碼

 

1.頭

 

#網(wǎng)頁(yè)頭
headers = {
    "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36",
    "referer" : "https://www.bilibili.com/"
}

 

2.獲取根評(píng)論


 
def get_rootReply(headers):
    num = 1
    replay_index = 1
    while True:
        URL = (f"https://api.bilibili.com/x/v2/reply/main?&jsonp=jsonp&next={num}&type=1&oid=470113786&mode=3&plat=1&_=1680096302818")   #獲得網(wǎng)頁(yè)源碼
        respond = requests.get(URL , headers = headers) # 獲得源代碼 抓包
        # print(respond.status_code)
        reply_num = 0
        if(respond.status_code == 200): # 如果響應(yīng)為200就繼續(xù),否則退出
            respond.encoding = "UTF-8"
            html = respond.text
            json_html = json.loads(html)    # 把格式轉(zhuǎn)化為json格式 一個(gè)是好讓pprint打印,一個(gè)是好尋找關(guān)鍵代碼
            
            if json_html['data']['replies'] is None or len(json_html['data']['replies']) == 0 :
                break
 
            for i in range(0,len(json_html['data']['replies'])):   #一頁(yè)只能讀取20條評(píng)論
                reply = json_html['data']['replies'][reply_num]['content']['message']
                root = json_html['data']['replies'][reply_num]['rpid']
                reply = reply.replace('\n',',')
                # print(reply)
                file.write(str(replay_index) + '.' + reply + '\n')
                if json_html['data']['replies'][reply_num]['replies'] is not None:
                    if(get_SecondReply(headers,root) == 0):
                        for i in range(0,len(json_html['data']['replies'][reply_num]['replies'])):
                            reply = json_html['data']['replies'][reply_num]['replies'][i]['content']['message']
                            reply = reply.replace('\n',',')
                            file.write("        " + reply + '\n')
                reply_num += 1 
                replay_index += 1
            num += 1
            
            time.sleep(0.5)
        else :
            print("respond error!")
            break
    file.close()

 

3.獲取子評(píng)論

 

def get_SecondReply(headers,root):
    pn = 1
    while True:
        URL = (f"https://api.bilibili.com/x/v2/reply/reply?jsonp=jsonp&pn={pn}&type=1&oid=824175427&ps=10&root={root}&_=1679992607971")
        respond = requests.get(URL , headers = headers) # 獲得源代碼 抓包
        reply_num = 0
        if(respond.status_code == 200):
            respond.encoding = "UTF-8"
            html = respond.text
            json_html = json.loads(html)
            
            if json_html['data']['replies'] is None:
                if(pn == 1):
                    return 0
                else :
                    return 1
            
            for i in range(0,len(json_html['data']['replies'])):
                if json_html['data']['replies'] is None:
                    break
                reply = json_html['data']['replies'][reply_num]['content']['message']
                reply = reply.replace('\n',',')
                # print(reply)
                reply_num += 1
                file.write("        " + reply + '\n')
            pn += 1
            time.sleep(0.5)
        else:
            print("Sreply error!")
            exit(-1)

 

這樣各個(gè)模塊就集齊了

 

四、總代碼

 

import requests
from bs4 import BeautifulSoup
import re
import json
from pprint import pprint
import time
 
#網(wǎng)頁(yè)頭
headers = {
    "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36",
    "referer" : "https://www.bilibili.com/"
}
 
file = open('lanyin.txt', 'w',encoding='utf-8')
 
def get_SecondReply(headers,root):
    pn = 1
    while True:
        URL = (f"https://api.bilibili.com/x/v2/reply/reply?jsonp=jsonp&pn={pn}&type=1&oid=824175427&ps=10&root={root}&_=1679992607971")
        respond = requests.get(URL , headers = headers) # 獲得源代碼 抓包
        reply_num = 0
        if(respond.status_code == 200):
            respond.encoding = "UTF-8"
            html = respond.text
            json_html = json.loads(html)
            
            if json_html['data']['replies'] is None:
                if(pn == 1):
                    return 0
                else :
                    return 1
            
            for i in range(0,len(json_html['data']['replies'])):
                if json_html['data']['replies'] is None:
                    break
                reply = json_html['data']['replies'][reply_num]['content']['message']
                reply = reply.replace('\n',',')
                # print(reply)
                reply_num += 1
                file.write("        " + reply + '\n')
            pn += 1
            time.sleep(0.5)
        else:
            print("Sreply error!")
            exit(-1)
 
    
def get_rootReply(headers):
    num = 1
    replay_index = 1
    while True:
        URL = (f"https://api.bilibili.com/x/v2/reply/main?&jsonp=jsonp&next={num}&type=1&oid=470113786&mode=3&plat=1&_=1680096302818")   #獲得網(wǎng)頁(yè)源碼
        respond = requests.get(URL , headers = headers) # 獲得源代碼 抓包
        # print(respond.status_code)
        reply_num = 0
        if(respond.status_code == 200): # 如果響應(yīng)為200就繼續(xù),否則退出
            respond.encoding = "UTF-8"
            html = respond.text
            json_html = json.loads(html)    # 把格式轉(zhuǎn)化為json格式 一個(gè)是好讓pprint打印,一個(gè)是好尋找關(guān)鍵代碼
            
            if json_html['data']['replies'] is None or len(json_html['data']['replies']) == 0 :
                break
 
            for i in range(0,len(json_html['data']['replies'])):   #一頁(yè)只能讀取20條評(píng)論
                reply = json_html['data']['replies'][reply_num]['content']['message']
                root = json_html['data']['replies'][reply_num]['rpid']
                reply = reply.replace('\n',',')
                # print(reply)
                file.write(str(replay_index) + '.' + reply + '\n')
                if json_html['data']['replies'][reply_num]['replies'] is not None:
                    if(get_SecondReply(headers,root) == 0):
                        for i in range(0,len(json_html['data']['replies'][reply_num]['replies'])):
                            reply = json_html['data']['replies'][reply_num]['replies'][i]['content']['message']
                            reply = reply.replace('\n',',')
                            file.write("        " + reply + '\n')
                reply_num += 1 
                replay_index += 1
            num += 1
            
            time.sleep(0.5)
        else :
            print("respond error!")
            break
    file.close()
 
if __name__ == '__main__':
    get_rootReply(headers)
    print("sucessful")

 

五、總結(jié)

        自己隨手寫的代碼,比較垃圾,歡迎大佬指正。

轉(zhuǎn)載自:https://blog.csdn.net/ClushioAqua/article/details/129834114