鱼C论坛

 找回密码
 立即注册
查看: 1121|回复: 1

通过任意b站视频爬取发布视频up主的所有视频弹幕

[复制链接]
发表于 2020-5-29 11:23:42 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
之前学完爬虫和自己捣鼓了selenium这个自动化模块写的小程序。
现在回过来使用时发现不能使用了,查明发现b站现在似乎改使用bv号而不是av号。细微改动后还是可以使用滴。

注:如果多次爬取相同的个人空间视频,可能会被反爬虫检测到,可自行使用proxy。


import requests
from bs4 import BeautifulSoup
import json
from selenium import webdriver
import time


class Bilibili_danmu:
    def __init__(self, start_url):
        self.start_url = start_url
        self.driver = webdriver.Chrome(r"D:\chromedriver.exe")
        self.pagelist_url = 'https://api.bilibili.com/x/player/pagelist?bvid={}'
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36'}
        self.danmu_url = 'https://api.bilibili.com/x/v1/dm/list.so?oid={}'

    def get_space_url(self, start_url):
        # 通过传入的视频获取up主的视频个人空间url地址
        self.driver.get(start_url)
        element = self.driver.find_element_by_xpath("//a[contains(@class,'username')]")
        space_url = element.get_attribute('href')

        return space_url

    def get_aid_list(self, space_url):
        # 获取个人空间一页(最多30个视频)的bv号列表
        # bilibili将视频av号改成了bv号,此处的aid_list(原av号)即现在获取的bvid的列表
        self.driver.get(space_url)
        elements = self.driver.find_elements_by_xpath("//ul[contains(@class,'cube-list')]//li")
        aid_list = []
        for each in elements:
            aid_list.append(each.get_attribute('data-aid'))
        return aid_list

    def get_cid_dict(self, aid):
        # 此方法用来获取每个视频是否分p,分p的话获取每一个子视频的cid
        pagelist_url = self.pagelist_url.format(aid)
        response = requests.get(pagelist_url, headers=self.headers)
        page_list = json.loads(response.content.decode())
        cid_dict = {}
        for each in page_list['data']:
            cid_dict[each['cid']] = each['part']
        return cid_dict

    def save_danmu(self, cid_dict):
        with open('danmu.txt', 'a', encoding='utf-8') as f:
            for each in cid_dict:
                f.write(cid_dict[each])
                f.write(':\n\n')
                danmu_url = self.danmu_url.format(each)
                r = requests.get(danmu_url, headers=self.headers)
                content = r.content.decode()
                soup = BeautifulSoup(content, 'xml')
                try:
                    result = (soup.find_all('d'))
                    for danmu in result:
                        f.write(danmu.string)
                        f.write('\n')
                except:
                    f.write('\n')

    def run(self):
        # 1通过获取任何一个视频的网址,得到所属up个人空间视频页的url
        space_url = self.get_space_url(self.start_url)
        num = 1
        while True:
            url = space_url + ('/video?page={}'.format(str(num)))
            print(url)
            # 2提取视频页第一页的所有视频的aid地址,做成列表
            aid_list = self.get_aid_list(url)
            print(aid_list)
            # 2.1 进入每一个aid对应的网址,获取是否当前视频有子视频,且提取所有子视频的对于弹幕xml文件。
            for aid in aid_list:
                cid_dict = self.get_cid_dict(aid)
                # 2.2 将每个xml文件的弹幕保存到本地
                self.save_danmu(cid_dict)
            if len(aid_list) < 30:
                # 如果当前个人空间页面的视频(aid)数量小于30,即已爬取到所有视频。停止循环
                break
            else:
                # 3若视频页第一页所获取的列表个数等于30,进入第二页视频页。
                # 3.1 循环2.1,2.2
                num += 1


if __name__ == '__main__':
    danmu = Bilibili_danmu('https://www.bilibili.com/video/BV1j4411c7ny')
    danmu.run()

评分

参与人数 1鱼币 +5 贡献 +1 收起 理由
heidern0612 + 5 + 1 鱼C有你更精彩^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-3-20 13:49:04 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-12 00:52

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表