【爬虫】爬取B站UP的所有视频细节信息(通过UP名字)

爬取B站UP主的所有视频细节信息

1. 前言

使用python来爬取B站UP的视频信息,在此之前需要安装一下模块

pip3 install selenium
pip3 install bs4

selenium是一个操作浏览器的Python库,需要安装相应的浏览器驱动。请自行安装。
本文实现了一个可以通过输入B站某个UP主的名字来进行爬取视频信息。

2. 爬取信息的数据结构

爬取的信息存储到JSON中,为以下组织方式:

{
    
    
    'name': XXX // 视频名称
    'author': XXX //作者名称
    'date': XXX //发布时间
    'url': XXX //视频链接
    'wachted': XXX //观看次数
    'bullet_comments' XXX //弹幕数量
    'liked': XXX //点赞数量
    'coin': XXX //投币数量
    'collected': XXX //收藏数量
    'shared': XXX //收藏数量
    'now_date': XXX //获取信息时间
}

以下为爬取到的信息:
爬取信息

3. 程序说明及注意

3.1 爬取不同UP主

通过更改代码中的

def get_page(upuser_name)

upuser_name 字段的值,可以实现爬取不同UP的视频信息。

3.2 错误说明

当爬取到数据为空时,是由于使用selenium未将网页加载出来,可将其后面sleep值调整的大一点(这里的大小和自己电脑的性能和网络有关,可以先自己操作浏览器判断需要时间,浏览器->F12->Network 刷新一下就可以看到)。

3.3 数据存储

由于爬取的时间较长,可以采用边爬取边存储的方式,以防设备出现故障(本文未采用)。

4. 代码

具体的信息在代码注释都有说明,自行查阅。

# 爬取bilibili up主的视频信息

'''
{
    'name': XXX // 视频名称
    'author': XXX //作者名称
    'date': XXX //发布时间
    'url': XXX //视频链接
    'wachted': XXX //观看次数
    'bullet_comments' XXX //弹幕数量
    'liked': XXX //点赞数量
    'coin': XXX //投币数量
    'collected': XXX //收藏数量
    'shared': XXX //收藏数量
    'now_date': XXX //获取信息时间
}
'''

from selenium import webdriver
import re
import json
from bs4 import BeautifulSoup
import time
from urllib import parse as url_parse
import datetime

class BSpider():

    def __init__(self):
        # 某个up主的视频页面,只需对pagenum字段进行替换切换不同的页面
        options = webdriver.FirefoxOptions()
        options.add_argument('--headless')
        self.main_url = 'https://space.bilibili.com/upuser_id/video?tid=0&page=page_num&keyword=&order=pubdate'
        self.browser = webdriver.Firefox(options=options)

    def close_webdriver(self):
        # 关闭相关驱动
        self.browser.quit()

    def locate2upuser(self, name_string):
        # 通过名字定位到该up主的ID号
        # url中文编码
        name_string = url_parse.quote(name_string)

        self.browser.get('https://search.bilibili.com/upuser?keyword='+name_string+'&page=1&order=fans&order_sort=0&user_type=3')
        time.sleep(3)

        # 获取当前up的个人链接
        uid = self.browser.find_element_by_xpath('//*[@id="user-list"]/div[1]/ul/li/div[2]/div[1]/a[1]').get_attribute('href')
        time.sleep(1)
        # 从链接中取得id
        uid = uid.split('/')[-1].split('?')[0]
        # print(uid)
        return uid

    def resub(self, url, r_pattern, value):
        # 正则替换
        pattern = re.compile(r_pattern)
        page_url = re.sub(pattern, value, url)
        return page_url
        
    def get_detial_list(self, url):
        # 获取某一页视频 url及名称 列表
        detial_url_list = []
        detial_name_list = []
        self.browser.get(url)
        time.sleep(2)
        html = BeautifulSoup(self.browser.page_source)

        for a_label in html.find('div', id = 'submit-video-list').find_all('a', attrs = {
    
    'target':'_blank', 'class':'title'}):
            if (a_label['href'] != None):
                detial_url_list.append('https:'+a_label['href'])
                detial_name_list.append(a_label.text)
        
        return detial_url_list, detial_name_list

    def get_pagenum(self, url):
        # 获取当前up的视频页数
        page_url = url
        page_url = self.resub(page_url, r'page_num', str(1))
        self.browser.get(page_url)
        time.sleep(1)
        html = BeautifulSoup(self.browser.page_source)

        page_number = html.find('span', attrs={
    
    'class':'be-pager-total'}).text
        return int(page_number.split(' ')[1])

    def get_digit_from_string(self, string):
        #print(string)
        return re.findall(r"\d+\.?\d*", string)[0]
        
    def get_video_detial(self, video_detial_dect):
        # 获取某个视频的基本信息

        url = video_detial_dect['url']
        self.browser.get(url)
        # 这里的时间设置的大一点,不然页面会加载不出来,
        # 导致获取到的信息为空 可以用浏览器先测试一下多少时间可以获取到这些页面资源 
        # 这个由自己电脑的性能和网络决定,出现空值的时候试着将sleep的值调大一点
        time.sleep(5)
        html = BeautifulSoup(self.browser.page_source)
        print(url)
        # 清洗数据获取信息 要进行正则替换去掉中文 保留数字
        try:
            video_detial_dect['watched'] = self.get_digit_from_string(html.find('span', attrs={
    
    'class':'view'})['title'])
            video_detial_dect['bullet_comments'] = self.get_digit_from_string(html.find('span', attrs={
    
    'class':'dm'})['title'])
            video_detial_dect['liked'] = self.get_digit_from_string(html.find('span', attrs={
    
    'class':'like'})['title'])
            video_detial_dect['coin'] = html.find('span', attrs={
    
    'class':'coin'}).get_text().strip()
            video_detial_dect['collected'] = self.get_digit_from_string(html.find('span', attrs={
    
    'class':'collect'})['title'])
            video_detial_dect['shared'] = html.find('span', attrs={
    
    'class':'share'}).get_text().strip().split('\n')[0]
            video_detial_dect['date'] = self.browser.find_element_by_xpath('//*[@id="viewbox_report"]/div/span[3]').text
            video_detial_dect['now_date'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') 
        except Exception as e:
            video_detial_dect['watched'] = ''
            video_detial_dect['bullet_comments'] = ''
            video_detial_dect['liked'] = ''
            video_detial_dect['coin'] = ''
            video_detial_dect['collected'] = ''
            video_detial_dect['shared'] = ''
            video_detial_dect['date'] = ''
            video_detial_dect['now_date'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') 
            print(e)
        print(video_detial_dect)
        return video_detial_dect

    def get_page(self, upuser_name):
        # 获取一个up 主下的所有视频
        uid = self.locate2upuser(upuser_name)
        url = self.resub(self.main_url, r'upuser_id', str(uid))
        
        # page_number = 1
        page_number = self.get_pagenum(url) # 页数
        # 视频url列表 名称列表
        detial_url_list = []
        detial_name_list = []

        for index in range(page_number):
            print("------------------------------------")
            print("page: %d" %(index+1))

            # 对于不同的页,进行正则替换
            page_url = url
            page_url = self.resub(page_url, r'page_num', str(index+1))
            print('page_url: %s' %page_url)
            detial_url_list_onepage, detial_name_list_onepage = self.get_detial_list(page_url)
            # 这里要用extend加到后面
            detial_url_list.extend(detial_url_list_onepage)
            detial_name_list.extend(detial_name_list_onepage)
        
        # print(detial_url_list)
        # print(detial_name_list)

        # 视频json
        video_detial_json = []
        for i in range(len(detial_url_list)):
            video_detial_dect = {
    
    }
            video_detial_dect['url'] = detial_url_list[i]
            video_detial_dect['author'] = upuser_name
            video_detial_dect['name'] = detial_name_list[i]
            video_detial_dect = self.get_video_detial(video_detial_dect)
            video_detial_json.append(video_detial_dect)
        # print(video_detial_json)

        
        print('dump to json file ...')
        with open(r'2020\Crawl\Bilibili\Item1\data\video_detial.json', 'w', encoding='utf-8') as f:
            json.dump(video_detial_json, f, ensure_ascii=False,sort_keys=True, indent=4)
        print('dump  file done.')


print("init....")
bilibili = BSpider()
print("init done.")
# 更改名字爬取不同的UP视频信息
bilibili.get_page('华农兄弟')
bilibili.close_webdriver()

猜你喜欢

转载自blog.csdn.net/qq_37753409/article/details/108997784