szqyyzh 发表于 2020-5-29 11:23:42

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

之前学完爬虫和自己捣鼓了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")
      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//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['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)
                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()

智霸 发表于 2022-3-20 13:49:04

{:10_257:}
页: [1]
查看完整版本: 通过任意b站视频爬取发布视频up主的所有视频弹幕