2021.11.8 python 爬虫教学B站爬取up全部视频弹幕,视频评论,视频信息代码讲解(最全、清晰易懂)
一.介绍
咳咳、、、这是我最近接到的一个单子,我心想干脆就放出来吧,网上几乎都是一些零零散散的教程,我来填补这类空缺!!!(啊!我被我这开源的精神给打动了,看完了点赞呗)
我们观察bilibili网站,看看我们要爬取的人,我这里选的是老番茄这位B站一哥。
二.弹幕
通过视频,分析怎么获得Bv号
首先是弹幕这一块,我们打开“老番茄”的B站主页,如下图 所示: 第一点,我们首先要做的是把思路理清楚,先干什么,然后干什么,思路很重要!!!!
我们要爬取一个up主所有的弹幕,是不是要先知道他发不过哪些作品,作品的数量,作品的BV号,通过BV号我们可以确定一条视频,比如:
观察规律,video/后面的就是BV号,所以我们说可以通过BV号锁定到视频url。那好接下来就好办了。
问题:我们从哪里获得BV号呢?
观察网站,作为一位爬虫工程师,你需要的就是观察网站,从网站下手。
我们可以看到有很多的视频url(地址),我们打开抓包工具(F12),看看这些视频是通过哪些api得到的。
我们发现网站是通过ajax来实现网站对数据的加载的,有同学会问,什么是ajax?我举一个很通俗易懂的例子给你听吧。就是网站不用换地址的情况下实现的数据加载,比如翻页,源地址并没有变,变的是内容。
找到json数据,看看api是什么
但是我们打不开是怎么回事?因为我们在博客园里打开肯定不行的!!!我们把它复制粘贴下来,到浏览器里打开。
我们观察api参数。
参数有以下几种,观察一组肯定发现不了什么,我们抓取下一页的json数据进行对比

我们观察看参数的变化,现在只有pn是变的,pn应该是页数,不确定?我们抓一下第三页的json数据
果然!!!!那么mid是什么呢?好眼熟哦。没错!他就是我们用户的id!打开老番茄主页,
uid的值就是json参数里的mid!!!
那么确定他有多少页呢?看投稿页面啊呀,我的傻宝。
现在我们已经获取的参数信息,现在开始写代码。
获得BV号,作者名字,保存到电子表格中的代码部分
具体json分析我这里不浪费口舌了,能看到我的博文说明还是有点水平的
我们下面的代码中有一个名叫xlsxwriter的包,具体是什么用法我发几张图片给大家领悟一下,实在不懂的评论区dd我。
import xlsxwriter as xw def xw_toExcel(data): # xlsxwriter库储存数据到excel workbook = xw.Workbook('演示数据.xlsx') # 创建工作簿 worksheet1 = workbook.add_worksheet("sheet1") # 创建子表 worksheet1.activate() # 激活表 title = ['第一标题','第二标题'] # 设置表头 worksheet1.write_row('A1', title) # 从A1单元格开始写入表头 i = 2 # 从第二行开始写入数据 for j in range(len(data)): insertData = [data[j]["第一标题"],data[j]["第二标题"]] row = 'A' + str(i) worksheet1.write_row(row, insertData) i += 1 workbook.close() # 关闭表 data = [ {'第一标题':'我从哪里来?','第二标题':'我诞生于星河'}, {'第一标题':'人为什么会思考?','第二标题':'呃。。。。。'}, {'第一标题':'巴拉巴拉巴拉?','第二标题':'啊吧啊吧啊吧'} ] xw_toExcel(data)
结果就是这样:
好了,是不是清晰易懂,实在不懂就把函数照套就行了。
然后就是总代码了。
import requests import json from time import sleep import xlsxwriter as xw #导入我们要的包 #现在进行headers封装 headers = { 'user-agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36' } def get_video(mid,page): #定义一个函数 mid参数就是up主的uid,page参数就是页数 all_Bv_list = [] #定义一个列表,把所有的url装进列表 for i in range(1,page+1): #for循环主要是用来确定页数 url = 'https://api.bilibili.com/x/space/arc/search?mid=' + str(mid) + '&ps=30&tid=0&pn=' + str(i) + '&keyword=&order=pubdate&jsonp=jsonp' #我们用字符串拼接来组成url Session = requests.session()#下面进行简单的初始化 sleep(1) json_data = Session.get(url,headers=headers).content#得到二进制数据 json_data = str(json_data,'utf8') #utf-8格式对二进制数据分析 json_data = json.loads(json_data)#封装json json_data = json_data['data']['list']['vlist']#获取json对应数据 for BV in json_data:#遍历对应数据 BV = BV['bvid']#得到BV号 video_url = 'https://www.bilibili.com/video/' + BV #拼接 all_Bv_list.append(video_url)# 添加列表 return all_Bv_list #返回值 def get_video_title(mid,page): all_title = [] for i in range(1, page + 1): url = 'https://api.bilibili.com/x/space/arc/search?mid=' + str(mid) + '&ps=30&tid=0&pn='+str(i)+'&keyword=&order=pubdate&jsonp=jsonp' Session_1 = requests.session() json_data = Session_1.get(url, headers=headers).content json_data = str(json_data, 'utf8') json_data = json.loads(json_data) json_data= json_data['data']['list']['vlist'] for BV in json_data: title = BV['title'] all_title.append(title) return all_title #跟上面一样,只不过我们要视频标题作为文件名 def get_video_up(mid): url = 'https://api.bilibili.com/x/space/arc/search?mid=' + str(mid) + '&ps=30&tid=0&pn=1&keyword=&order=pubdate&jsonp=jsonp' Session_1 = requests.session() json_data = Session_1.get(url,headers=headers).content json_data = str(json_data,'utf8') json_data = json.loads(json_data) json_data_author = json_data['data']['list']['vlist'][0]['author'] return json_data_author #获得up主名字 def xw_toExcel(data): # xlsxwriter库储存数据到excel workbook = xw.Workbook('弹幕数据.xlsx') # 创建工作簿 worksheet1 = workbook.add_worksheet("sheet1") # 创建子表 worksheet1.activate() # 激活表 title = ['up主','平台','视频标题','弹幕内容','第一参数','第二参数','第三参数','第四参数','第五参数','第六参数','第七参数','第八参数'] # 设置表头 worksheet1.write_row('A1', title) # 从A1单元格开始写入表头 i = 2 # 从第二行开始写入数据 for j in range(len(data)): insertData = [data[j]["up主"],data[j]["平台"],data[j]['视频标题'],data[j]['弹幕内容'],data[j]['第一参数'],data[j]['第二参数'],data[j]['第三参数'],data[j]['第四参数'],data[j]['第五参数'],data[j]['第六参数'],data[j]['第七参数'],data[j]['第八参数']] row = 'A' + str(i) worksheet1.write_row(row, insertData) i += 1 workbook.close() # 关闭表
遍历视频列表,获得弹幕
得到视频地址后我们就可以对每个视频url发起一个请求,看看每个网页中的弹幕是通过哪些api请求到的。
可是我对每个视频的url进行抓包,并没有得到对应的api,这是为什么呢?
随后我去了百度,发现了视频中的弹幕都是加载好的,然后放进视频里的,我想也对,要是不这么做的话,不得卡死。上网搜索的到官方的弹幕地址,
https://comment.bilibili.com/'+str(cid)+'.xml 类似
那些数字的意思就是:
我们给他爬下来
cid是通过视频网页源码获取的,我们可以用正则提取,response是指网页源码.
得到cid后我们就可以进行写代码了,我们把上面的代码写入一个py文件里,通过导入的方法调用函数
import requests import time import re from lxml import etree #导包 import all_url_list mid = int(input('id:')) page = int(input('页数:')) urls = all_url_list.get_video(mid,page) title = all_url_list.get_video_title(mid,page) author = all_url_list.get_video_up(mid) #调用方法 headers = { 'user-agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36' } i = 0 Session = requests.session() #封装 TextData = [] for url in urls: times = 0 response = Session.get(url,headers=headers).text cid = re.findall("\"cid\":([0-9]*),", response)[0] #获得cid dm_url = 'https://comment.bilibili.com/'+str(cid)+'.xml' response_1 = Session.get(dm_url,headers=headers) xml = etree.fromstring(response_1.content) all_dm = xml.xpath("/i/d/text()") p = xml.xpath("/i/d/@p") # print(p[0].split(',')) # break for dm in all_dm:#添加数据 numbers = p[times].split(',') Data = { 'up主':'None','平台':'None','视频标题':'None','弹幕内容':'None','第一参数':'None','第二参数':'None','第三参数':'None','第四参数':'None','第五参数':'None','第六参数':'None','第七参数':'None','第八参数':'None', } Data['up主'] = author Data['平台'] = 'B站' Data['视频标题'] = title[i] Data['弹幕内容'] = dm Data['第一参数'] = numbers[0] Data['第二参数'] = numbers[1] Data['第三参数'] = numbers[2] Data['第四参数'] = numbers[3] Data['第五参数'] = numbers[4] Data['第六参数'] = numbers[5] Data['第七参数'] = numbers[6] Data['第八参数'] = numbers[7] times += 1 TextData.append(Data) #循环写入,懂我意思吧 i += 1 print('第%d,ok!'% i ) all_url_list.xw_toExcel(data=TextData)#写入 print('全部视频数据下载完成')
我们看看效果,因为我之前爬的是李子柒的,我就不浪费时间爬了

看到有50w的弹幕,真可怕!
二,爬取视频信息和爬取视频评论
好了,写下来就是我们的主菜啦!!!!
首先分析,没错还是分析分析,想清楚自己要从哪一步入手?
是不是从网站入手啊,然后打开我们的视频链接
找到评论,看看是那个api请求到的。打开开发者工具,按照上面的操作步骤
为什么还是访问失败,我们把一些参数去掉,因为我们不需要参数进行js处理。
可以发现我们访问成功了
接下来我们看看参数是什么 意思,

next应该是下一页的意思
那oid是什么呢?在哪里获取呢,我这里直接告诉大家,oid就是网站的aid,我们可以用re来直接获取。跟上面cid一样的
我们拿到json数据后进行解析,解析步骤我也不讲了,都应该懂吧。
下面导入全部代码,让大家一次看过瘾
import json import requests from lxml import etree from time import sleep import re import xlsxwriter as xw import random from all_url_list import get_video,get_video_up #还是导入我们的模块包 USER_AGENTS = [ "Mozilla/5.0 (Windows; U; Windows NT 5.2) Gecko/2008070208 Firefox/3.0.1", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1", "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1", "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11", "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)", "Opera/9.80 (Windows NT 5.1; U; zh-cn) Presto/2.9.168 Version/11.50", "Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0", "Mozilla/5.0 (Windows NT 5.2) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; 360SE)", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 SE 2.X MetaSr 1.0", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2)", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT)", "Mozilla/5.0 (Windows; U; Windows NT 5.2) Gecko/2008070208 Firefox/3.0.1", "Mozilla/5.0 (Windows; U; Windows NT 5.1) Gecko/20070309 Firefox/2.0.0.3", "Mozilla/5.0 (Windows; U; Windows NT 5.1) Gecko/20070803 Firefox/1.5.0.12 " ] #进行UA伪装 mid = int(input('输入用户的UID账号:')) page = int(input('用户一共有几页:')) urls = get_video(mid,page) #获取视频一共的页数,跟爬取弹幕是一样的,因为导入的是同一个包 author = get_video_up(mid=mid) TextData_vedio = [] TextData_comment = [] #定义两个列表来存视频信息和视频评论 #这是视频评论的 def xw_toExcel_comment(data): # xlsxwriter库储存数据到excel workbook = xw.Workbook('总评论数据.xlsx') # 创建工作簿 worksheet1 = workbook.add_worksheet("sheet1") # 创建子表 worksheet1.activate() # 激活表 title = ['up主','平台','视频标题','用户','id','等级','性别','签名','评论'] # 设置表头 worksheet1.write_row('A1', title) # 从A1单元格开始写入表头 i = 2 # 从第二行开始写入数据 for j in range(len(data)): insertData = [data[j]["up主"],data[j]["平台"],data[j]['视频标题'], data[j]["用户"],data[j]['id'] ,data[j]["等级"],data[j]["性别"],data[j]["签名"],data[j]['评论']] row = 'A' + str(i) worksheet1.write_row(row, insertData) i += 1 workbook.close() # 关闭表 #这是视频信息的 def xw_toExcel_vedio(data): # xlsxwriter库储存数据到excel workbook = xw.Workbook('总数据.xlsx') # 创建工作簿 worksheet1 = workbook.add_worksheet("sheet1") # 创建子表 worksheet1.activate() # 激活表 title = ['平台','视频标题','视频播放量','弹幕量','发布时间','点赞数量','硬币数量','收藏','转发'] # 设置表头 worksheet1.write_row('A1', title) # 从A1单元格开始写入表头 i = 2 # 从第二行开始写入数据 for j in range(len(data)): insertData = [data[j]["平台"],data[j]["视频标题"], data[j]["视频播放量"], data[j]["弹幕量"],data[j]["发布时间"],data[j]["点赞数目"],data[j]["硬币数量"],data[j]["收藏"],data[j]['转发']] row = 'A' + str(i) worksheet1.write_row(row, insertData) i += 1 workbook.close() # 关闭表 # 设置headers headers = { 'user-agent' : random.choice(USER_AGENTS), } Session = requests.session() #实例化对象 video_number = 0 #设置一个提醒操作,主要用来知道爬取到哪里了 try: for url in urls: #将上面的url列表进行遍历 number = 1 #申明 #下面都属于解析 response = Session.get(url=url,headers=headers).text #因为只有视频评论是动态加载的,所以这里我们可以直接爬取网页源代码 tree = etree.HTML(response) title = tree.xpath('//*[@id="viewbox_report"]/h1/@title')[0] #视频标题 video_playback_volume = tree.xpath('//*[@id="viewbox_report"]/div/span[1]/text()')[0]#视频播放量 Number_of_video_barrages = tree.xpath('//*[@id="viewbox_report"]/div/span[2]/text()')[0]#弹幕量 video_time = tree.xpath('//*[@id="viewbox_report"]/div/span[3]/text()')[0]#发布时间 video_likes = tree.xpath('//*[@id="arc_toolbar_report"]/div[1]/span[1]/@title')[0] #点赞数量 video_coin = tree.xpath('//*[@id="arc_toolbar_report"]/div[1]/span[2]/text()')[0] #硬币数量 video_collect = tree.xpath('//*[@id="arc_toolbar_report"]/div[1]/span[3]/text()')[0] #收藏 video_forward = tree.xpath('//*[@id="arc_toolbar_report"]/div[1]/span[4]/text()')[0] #转发 # #以上获得了视频信息的内容 oid = re.findall("\"aid\":([0-9]*),", response)[0] #获得oid #定义一个字典 vedio_Data = { '平台':'None','视频标题':'None', '视频播放量': 'None', '弹幕量':'None', '发布时间': 'None', '点赞数目': 'None', '硬币数量': 'None', '收藏': 'None', '转发': 'None' } vedio_Data['平台'] = 'B站' vedio_Data['视频标题'] = str(title) vedio_Data['视频播放量'] = str(video_playback_volume) vedio_Data['弹幕量'] = str(Number_of_video_barrages) vedio_Data['发布时间'] = str(video_time) vedio_Data['点赞数目'] = str(video_likes) vedio_Data['硬币数量'] = str(video_coin) vedio_Data['收藏'] = str(video_collect) vedio_Data['转发'] = str(video_forward) TextData_vedio.append(vedio_Data)#添加到列表 #接下来一直爬视频评论了 while True: comment_url = 'https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next='+str(number)+'&type=1&oid='+str(oid)+'&mode=3&plat=1' number += 1 json_data = Session.get(url=comment_url,headers=headers).content sleep(1) json_data = json.loads(json_data) #获得字典数据 #下面进行数据分析 replien = json_data['data']['replies'] print('第%d页'%number) if replien != None: #因为当字典里replien等于Null时,我们的评论就爬完了,所以我们当replien不等于None是进行数据的持久化存储 for data in replien: data_comment = data['content']['message'] #评论内容 data_id = data['mid'] #用户的id data_level = data['member']['level_info']['current_level']#等级 data_name = data['member']['uname'] #用户的名字 data_sex = data['member']['sex'] #用户的性别 data_sign = data['member']['sign']#用户的个性签名 # data_like = data['like']#评论点赞数 Data = { 'up主':'None', '平台':'None', '视频标题':'None', '用户':'None', 'id':'None','等级':'None', '性别':'None', '签名':'None', '评论':'None' } Data['up主'] = author Data['平台'] = 'B站' Data['视频标题'] = title Data['用户'] = data_name Data['id'] = data_id Data['等级'] = data_level Data['性别'] = data_sex Data['签名'] = data_sign Data['评论'] = data_comment TextData_comment.append(Data) else: #当为None时我们就返回爬完了,爬取下一个视频 video_number = video_number + 1 print('第%d个视频爬取完毕'% video_number) break #接下来就是调用函数保存啦!! except: xw_toExcel_comment(TextData_comment) xw_toExcel_vedio(TextData_vedio) else: xw_toExcel_comment(TextData_comment) xw_toExcel_vedio(TextData_vedio)
接下来看看成果,因为我爬取得还是李子柒哈哈哈,单纯的懒因为是爬好的,效果
都差不多。
接下来是评论信息,我这里是滇西小哥的
以上就是代码的全部了,希望你能喜欢!
代码的使用
我们双击弹幕.py
输入up主的UID,和一共有多少页


好了,看看视频怎么使用
看完点个赞呗!!!
注意!!!本文章没有我的允许,禁止转载,如果被我找到,我会拿起法律武器进行维权!!!
注意!!!本文章没有我的允许,禁止转载,如果被我找到,我会拿起法律武器进行维权!!!
注意!!!本文章没有我的允许,禁止转载,如果被我找到,我会拿起法律武器进行维权!!!
注意!!!本文章没有我的允许,禁止转载,如果被我找到,我会拿起法律武器进行维权!!!
注意!!!本文章没有我的允许,禁止转载,如果被我找到,我会拿起法律武器进行维权!!!
注意!!!本文章没有我的允许,禁止转载,如果被我找到,我会拿起法律武器进行维权!!!
注意!!!本文章没有我的允许,禁止转载,如果被我找到,我会拿起法律武器进行维权!!!

















浙公网安备 33010602011771号