blibli任意搜索关键字,相关视频的弹幕数据采集

参考网址:B站蔡徐坤

爬虫逻辑:【分页url采集】-【视频页面url采集】-【视频页面数据采集 / cid信息 / 弹幕xml数据采集】

弹幕xml网址示例:https://comment.bilibili.com/84682646.xml(通过cid获取弹幕的网址,后面会详细介绍)

要求

1)函数式编程
函数1:get_outer_urls(n) → 【分页网址url采集】
        n:爬取页数
        结果:得到分页网页的list
函数2:get_inner_urls(ui,d_h,d_c) → 【视频页面url采集】
        ui:分页网址
        d_h:user-agent信息
        d_c:cookies信息
        结果:得到一个视频页面的list
函数3:get_data(ui,d_h,d_c,table) → 【视频页面数据采集 / cid信息 / 弹幕xml数据采集】
        ui:视频页面网址
        d_h:user-agent信息
        d_c:cookies信息
        table:mongo集合对象

2)采集字段
① 视频页面数据采集(标题、时间、cid)

② 弹幕信息采集

步骤分解

步骤一、前期准备并封装第一个函数

1)导入相关的库,和设置代码分开标识

2)分析网页的规律,查看网页的2-4页(一般选取2-4就可以看出规律),网址如下:

u2 = https://search.bilibili.com/all?keyword=%E8%94%A1%E5%BE%90%E5%9D%A4&page=2
u3 = https://search.bilibili.com/all?keyword=%E8%94%A1%E5%BE%90%E5%9D%A4&page=3
u4 = https://search.bilibili.com/all?keyword=%E8%94%A1%E5%BE%90%E5%9D%A4&page=4
......

通过url分析,可知除了最后面的“page=”后面的数字随着页面在变化外,几乎没有变化。比如获取有关蔡徐坤20页的视频内容(每页包含了20个视频),创建20个url如下

urllst = []
for i in range(20):ui = f'https://search.bilibili.com/all?keyword=%E8%94%A1%E5%BE%90%E5%9D%A4&page={i+1}'urllst.append(ui)

输出结果为:

3) 封装第一个函数

def get_outer_urls(n):'''【分页网址url采集】n:爬取页数结果:得到分页网页的list'''urllst = []for i in range(n):ui = f'https://search.bilibili.com/all?keyword=%E8%94%A1%E5%BE%90%E5%9D%A4&page={i+1}'urllst.append(ui)return urllstprint(get_outer_urls(20))

输出结果为:(当输入20时,结果输出和上面的一致,证明封装第一个函数完成)

步骤二、设置请求头headers和登录信息cookies

这一步需要用户登录,没有账号的话,需要进行注册,cookies和headers的获取方式如下,

文字详述: 以上面的登录后的网页界面为例,鼠标右键检查,然后选择右边标签Network,然后刷新一下该网页,这时候在右方Doc下面的Name菜单栏下会出现一个新的信息,选择第一个文件,然后拉到底,就可以找到cookies和headers的信息。

步骤归纳:【登录的页面】–> 【右键检查】–> 【Network】–> 【刷新】–> 【Doc下面的Name菜单栏】–> 【点击第一个文件下拉到底】–> 【Request Headers下】

图示

查找到headers和cookies之后,将其写入到字典中储存,如下(代码在spyder里运行)

dic_headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"}cookies = "_uuid=3D3C1683-5F16-D3EC-36E2-5967E731F7DA81323infoc; buvid3=3EB2F2F9-8EE3-4AFE-B3D6-7620A3B2E636155823infoc; LIVE_BUVID=AUTO4015671567822432; sid=bj42fy4m; CURRENT_FNVAL=16; stardustvideo=1; rpdid=|(umYuYRkm~|0J'ulY~ul~JlY; UM_distinctid=16ce1f17c989db-0c9243ec350826-e343166-144000-16ce1f17c99a18; CURRENT_QUALITY=0; DedeUserID=38449436; DedeUserID__ckMd5=272068a4511232d7; SESSDATA=3a11597f%2C1583975698%2C7bfdfc21; bili_jct=d8d63e8aa5a2eb9adf9f30698873d271"
dic_cookies = {}
for i in cookies.split("; "):dic_cookies[i.split("=")[0]] = i.split("=")[1]print(dic_headers)
print(dic_cookies)

输出结果如下:

步骤三、网页信息请求和网页初解析

首先尝试进行网页信息请求,代码如下

url = 'https://search.bilibili.com/all?keyword=%E8%94%A1%E5%BE%90%E5%9D%A4'
r = requests.get(url,headers = dic_headers, cookies = dic_cookies)
print(r)

输出结果为:<Response [200]> (说明网站信息可以正常访问,接下来进行页面的解析)

在网页界面鼠标右键,选择检查,可以发现,搜到的视频都是在【ul】标签下的【li】标签里面,如下

代码实现视频信息的获取,如下

soup = BeautifulSoup(r.text, 'lxml')
lis = soup.find('ul',class_="video-list clearfix").find_all('li')
print(lis[0])

输出结果如下:(和第一个视频的信息对应上,而且输出的内容里面包含了标题和上传的时间信息)

接着就可以获取该视频的url,至于标题和上传时间,可以再进入该url页面后进行获取,通过上面的输出,可以发现url在【li】标签下的【a】的href属性里面

li_0 = lis[0]
url_inner = li_0.a['href']
print(url_inner)

输出的结果如下:(最后输出的标题都是没有https,可以在封装函数输出的时候加上)

至此获取第一个视频的url的试错就成功了,接下来就是封装第二个函数了

步骤四、封装第二个函数

上面实现了单个视频url的获取,接下来只需要进行遍历循环并把结果储存到列表即可,也就是封装第二个函数的要求,代码如下

def get_inter_urls(ui,d_h,d_c):'''【视频页面url采集】ui:视频信息网页urld_h:user-agent信息d_c:cookies信息结果:得到一个视频页面的list'''ri = requests.get(ui, headers = d_h, cookies = d_c)soupi = BeautifulSoup(ri.text, 'lxml')lis = soupi.find('ul',class_="video-list clearfix").find_all('li')lst = []for li in lis:lst.append('https:' + li.a['href'])return lsturl = 'https://search.bilibili.com/all?keyword=%E8%94%A1%E5%BE%90%E5%9D%A4'
#这里的url就是第一页的分页网址
print(get_inter_urls(url,dic_headers,dic_cookies))

输出的结果为:(封装的第二个函数可以正常调用)

步骤五、网页深度解析(获取标题、时间和弹幕)并将数据存入数据库

1) 获取标题
和之前的网页初解析一样,找到标题所对应的的标签信息,如下

① 可以看出这里面有个id的属性,可以直接用来获取标题信息(标题信息文本数据在其下面的【span】标签下第一个),代码如下

urllst = get_outer_urls(20) #获取前20页的网址
u1 = urllst[0] #获取第一页的全部20个视频url
url_inter_1 = get_inter_urls(u1,dic_headers,dic_cookies)[0] #获取第一个视频的url
ri = requests.get(url_inter_1, headers = dic_headers,cookies =dic_cookies)
soupi = BeautifulSoup(ri.text, 'lxml')
title = soupi.find(id = "viewbox_report").span.text
print(title)

输出的结果为:(和第一个视频的标题一致)

② 补充:也可以通过查找h1标签,然后使用.h1[‘title’]直接获取(较为简单)

2) 获取上传时间
定位到第一个视频的url位置,前面1)获取标题时候已经做了,只需要在下面输入获取上传时间的代码就可以了,从下面的标签中可以看出,上传时间是在【div class=‘video-data’】标签下的【span】里面

直接使用如下代码看看能否获取文本信息

upload_time = soupi.find("div",class_ ="video-data").text
print(upload_time)

输出的结果为:

输出结果并不是我们希望得到的,原因是这里面有两个【span】标签,可以使用.next_subling兄弟标来获取上传时间的文本信息也可以使用正则表达式获取文本信息(find()方法是获取找到的第一个标签,那么它的兄弟节点就是第二个目标标签了)

① 使用find()方法配合兄弟节点匹配文本信息,代码如下

upload_time = soupi.find("span", class_ = "a-crumbs").next_sibling.text
print(upload_time)

输出的结果为:

② 使用正则表达式匹配文本信息(目标字段是以‘20’开头的,以数字结尾),代码如下

upload_time = re.search(r'(20.*\d)',soupi.find("div",class_ ="video-data").text)
print(upload_time.group(1))

输出的结果为:

3) 获取弹幕数据
① 解析一下cid
首先要从 B 站弹幕的说起,B 站视频的 ID 名字是 cid,一个 AV (视频)号下如果有多个分 P,就会占用多个 cid,cid 可以看做是视频的唯一 ID,通过这个 ID ,我们可以读取到 B 站的弹幕格式为 comment.bilibili.com/[cid].xml,在一开始给出的弹幕网址就为:https://comment.bilibili.com/84682646.xml

比如在第一个视频的网页界面点击鼠标右键查看源代码,然后搜索“cid”,就会发现相关的信息

复制"cid":后的数字查看一下这个信息在“检查”界面对应的标签的信息是怎么样的,搜索如下,可以看出都是在【script】标签下面

② cid 数据采集
对比“源代码"和"检查"页面,发现可以很好的获取cid的方式是通过在源代码窗口下查找,因为这里面的数据直接以字典的形式存储的,而如果再"检查"界面进行匹配标签,在来查找内容就显着很复杂,代码如下

cid = re.search(r'"cid":(\d*),', ri.text).group(1)
print(cid)

输出结果如下:(由此就获取了cid信息)

③ 弹幕信息采集
这里只需要将对应位置的数字换成cid信息即可,然后尝试获取该cid对应的url下面的内容(注意乱码的解决方式)

cid = re.search(r'"cid":(\d*),', ri.text).group(1)
cid_url = f"https://comment.bilibili.com/{cid}.xml"
r2 = requests.get(cid_url)
r2.encoding = r2.apparent_encoding
soup2 = BeautifulSoup(r2.text, 'lxml')
print(soup2)

输出的结果为:(部分结果截图)

检验能否获取正常数据(一般一个网页是会存放最新更新的1000条弹幕,因此可以通过列表的长度进行判断)

dmlst = re.findall(r'<d.*?>',r2.text)
print(dmlst,len(dmlst))

输出的结果为:

弹幕的标签信息全部存储到了dmlst里面了,接下来是提取里面的内容,顺便把之前的内容也写入到字典里面

for dm in dmlst:dic = {}dic['标题'] = titledic['上传时间'] = upload_timedic['cid'] = ciddic['弹幕内容'] = re.search(r'>(.*)<',dm).group(1)dic['其他信息'] = re.search(r'p="(.*)">',dm).group(1)print(dic)

输出结果为:

至此,就把相应的数据全部储存在字典里面了,接下来就是配置数据库和封装第三个函数了

步骤六、配置数据库和封装第三个函数

1) 配置数据库

import pymongo
myclient = myclient = pymongo.MongoClient("mongodb://localhost:27017/")
db = myclient['blibli']
datatable = db['data']

上述代码实现数据库的创建及命名,以及存放数据表格的创建

2)封装第三个函数,并将数据写入到数据库

只需要将每次生成的dic直接插入到创建的数据表格中即可,为了可视化储存过程,可以进行计数统计

def get_data(ui,d_h,d_c,table):'''ui:视频页面网址d_h:user-agent信息d_c:cookies信息table:mongo集合对象'''ri = requests.get(url = ui, headers = d_h, cookies = d_c)soupi = BeautifulSoup(ri.text, 'lxml')#title = soupi.find(id = "viewbox_report").span.texttitle = soupi.h1['title']upload_time = soupi.find("span", class_ = "a-crumbs").next_sibling.text#upload_time = re.search(r'(20.*\d)',soupi.find("div",class_ ="video-data").text)cid = re.search(r'"cid":(\d*),', ri.text).group(1)cid_url = f"https://comment.bilibili.com/{cid}.xml"r2 = requests.get(cid_url)r2.encoding = r2.apparent_encodingdmlst = re.findall(r'<d.*?/d>',r2.text)n = 0for dm in dmlst:dic = {}dic['标题'] = titledic['上传时间'] = upload_timedic['cid'] = ciddic['弹幕内容'] = re.search(r'>(.*)<',dm).group(1)dic['其他信息'] = re.search(r'p="(.*)">',dm).group(1)table.insert_one(dic)n += 1 return n

最后的运行代码(错误异常处理和可视化输出,这里只以第一页的视频中的弹幕数为例)

urllst = get_outer_urls(20) #获取前20页的网址
u1 = urllst[0] #获取第一页的全部20个视频url
url_inter = get_inter_urls(u1,dic_headers,dic_cookies) #获取第一个视频的urlerrorlst =[]
count = 0
for u in url_inter:try:count += get_data(u,dic_headers,dic_cookies,datatable)print('数据采集并存入成功,总共采集{}条数据'.format(count))except:errorlst.append(u)print('数据采集失败,数据网址为:',u)

输出为:这里调试的时候可以将第三个函数里面的table.insert_one(dic)注释掉,查看是否有数据采集成功的输出,如下

全部代码以及输出结果如下

import re
import requests
from bs4 import BeautifulSoup
import pymongodef get_outer_urls(n):'''【分页网址url采集】n:爬取页数结果:得到分页网页的list'''urllst = []for i in range(n):ui = f'https://search.bilibili.com/all?keyword=%E8%94%A1%E5%BE%90%E5%9D%A4&page={i+1}'urllst.append(ui)return urllstdef get_inter_urls(ui,d_h,d_c):'''【视频页面url采集】u:起始网址d_h:user-agent信息d_c:cookies信息结果:得到一个视频页面的list'''ri = requests.get(ui, headers = d_h, cookies = d_c)soupi = BeautifulSoup(ri.text, 'lxml')lis = soupi.find('ul',class_="video-list clearfix").find_all('li')lst = []for li in lis:lst.append('https:' + li.a['href'])return lstdef get_data(ui,d_h,d_c,table):'''ui:视频页面网址d_h:user-agent信息d_c:cookies信息table:mongo集合对象'''ri = requests.get(url = ui, headers = d_h, cookies = d_c)soupi = BeautifulSoup(ri.text, 'lxml')#title = soupi.find(id = "viewbox_report").span.texttitle = soupi.h1['title']upload_time = soupi.find("span", class_ = "a-crumbs").next_sibling.text#upload_time = re.search(r'(20.*\d)',soupi.find("div",class_ ="video-data").text)cid = re.search(r'"cid":(\d*),', ri.text).group(1)cid_url = f"https://comment.bilibili.com/{cid}.xml"r2 = requests.get(cid_url)r2.encoding = r2.apparent_encodingdmlst = re.findall(r'<d.*?/d>',r2.text)n = 0for dm in dmlst:dic = {}dic['标题'] = titledic['上传时间'] = upload_timedic['cid'] = ciddic['弹幕内容'] = re.search(r'>(.*)<',dm).group(1)dic['其他信息'] = re.search(r'p="(.*)">',dm).group(1)table.insert_one(dic)n += 1 return nif __name__ == '__main__':dic_headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"}cookies = "_uuid=3D3C1683-5F16-D3EC-36E2-5967E731F7DA81323infoc; buvid3=3EB2F2F9-8EE3-4AFE-B3D6-7620A3B2E636155823infoc; LIVE_BUVID=AUTO4015671567822432; sid=bj42fy4m; CURRENT_FNVAL=16; stardustvideo=1; rpdid=|(umYuYRkm~|0J'ulY~ul~JlY; UM_distinctid=16ce1f17c989db-0c9243ec350826-e343166-144000-16ce1f17c99a18; CURRENT_QUALITY=0; DedeUserID=38449436; DedeUserID__ckMd5=272068a4511232d7; SESSDATA=3a11597f%2C1583975698%2C7bfdfc21; bili_jct=d8d63e8aa5a2eb9adf9f30698873d271"dic_cookies = {}for i in cookies.split("; "):dic_cookies[i.split("=")[0]] = i.split("=")[1]urllst = get_outer_urls(20) #获取前20页的网址u1 = urllst[0] #获取第一页的全部20个视频urlurl_inter = get_inter_urls(u1,dic_headers,dic_cookies) #获取第一个视频的urlmyclient = myclient = pymongo.MongoClient("mongodb://localhost:27017/")db = myclient['blibli']datatable = db['data']#get_data(url_inter[0],dic_headers,dic_cookies,datatable)errorlst =[]count = 0for u in url_inter:try:count += get_data(u,dic_headers,dic_cookies,datatable)print('数据采集并存入成功,总共采集{}条数据'.format(count))except:errorlst.append(u)print('数据采集失败,数据网址为:',u)    

输出的结果如下:

发现最后上传动态的图片时间较短,没有把最后数据写入到数据库的界面录上去,又重新从把后面的补上了,如下

【python爬虫专项(19)】blibli弹幕数据爬取(以全站搜索蔡徐坤的视频为例)相关推荐

  1. Python爬虫《自动化学报》数据爬取与数据分析

    Python爬虫<自动化学报>数据爬取与数据分析 文章目录 Python爬虫<自动化学报>数据爬取与数据分析 前言 一.代码 二.结果展示 三.爬虫实现 1.准备 2.获取网页 ...

  2. python爬虫,g-mark网站图片数据爬取及补坑

    应用python对g-mark网站图片数据爬取,同时但对于数据抓取失败的图片进行补坑(重新爬取操作),由于是日本网站,没有梯子访问的话,特别容易访问超时,比较合适的补坑操作是直接将数据采集到数据库,而 ...

  3. Python爬虫-CSDN博客排行榜数据爬取

    文章目录 前言 网络爬虫 搜索引擎 爬虫应用 谨防违法 爬虫实战 网页分析 编写代码 运行效果 反爬技术 前言 开始接触 CTF 网络安全比赛发现不会写 Python 脚本的话简直寸步难行--故丢弃 ...

  4. (python爬虫)新浪新闻数据爬取与清洗+新浪新闻数据管理系统+MySQL

    新浪新闻数据爬取与清洗+新浪新闻数据管理系统 设计要求 新浪新闻数据爬取与清洗 基本要求:完成新浪新闻排行中文章的数据爬取,包括标题.媒体.时间.内容. 进阶要求:对最近一周出现次数最多的关键字排名并 ...

  5. Python爬虫实习笔记 | Week4 项目数据爬取与反思

    2018/11/05 1.所思所想: 今天我把Python爬虫实战这本书Chapter6看完,很有感触的一点是,书本中对爬虫实现的模块化设计很给我灵感,让我对项目中比较无语的函数拼接有了解决之道,内省 ...

  6. python爬虫多久能学会-不踩坑的Python爬虫:如何在一个月内学会爬取大规模数据...

    原标题:不踩坑的Python爬虫:如何在一个月内学会爬取大规模数据 Python爬虫为什么受欢迎 如果你仔细观察,就不难发现,懂爬虫.学习爬虫的人越来越多,一方面,互联网可以获取的数据越来越多,另一方 ...

  7. python爬取app播放的视频,Python爬虫工程师必学——App数据抓取实战视频教程

    爬虫分为几大方向,WEB网页数据抓取.APP数据抓取.软件系统数据抓取.本课程主要为同学讲解如何用python实现App数据抓取,课程从开发环境搭建,App爬虫必备利器详解,项目实战,到最后的多App ...

  8. python爬虫入门实战---------一周天气预报爬取_Python爬虫入门实战--------一周天气预报爬取【转载】【没有分析...

    Python爬虫入门实战--------一周天气预报爬取[转载][没有分析 Python爬虫入门实战--------一周天气预报爬取[转载][没有分析] 来源:https://blog.csdn.ne ...

  9. 基于python爬虫————静态页面和动态页面爬取

    基于python爬虫----静态页面和动态页面爬取 文章目录 基于python爬虫----静态页面和动态页面爬取 1. 爬虫的原理 2. 用正则表达式匹配获取数据 3. 页面源码解析 4. 通过req ...

最新文章

  1. linux dump用法,Linux命令之tcpdump命令用法介绍
  2. L1-003 个位数统计
  3. 十八、梯度下降与反向传播
  4. mysql5.7半自动同步设置【转】
  5. 计算机第二课堂教学计划,小学的第二课堂教学计划
  6. 理解三值逻辑与NULL,你离SQL高手更近了一步
  7. Linux 容器 vs 虚拟机 —— 谁更胜一筹
  8. HTC vive 虚实融合
  9. CS231n李飞飞计算机视觉 循环神经网络
  10. 6.0后,全局悬浮窗或者弹窗不显示的解决办法
  11. 模板 | 年度财务分析报告财务工作汇报PPT
  12. 苹果发布会总结:Mac 三产品线更新自研 M1 芯片,尝鲜只要 5299 元
  13. SMS发送流程 Android2.2
  14. 一剑走江湖---武汉
  15. 2021 春季新品发布会上,苹果推出了全新配件 AirTag
  16. 蜜蜂在挡板外和框梁顶造赘脾的几个要素及处理方法
  17. 删除360天擎(企业版)---不知道密码情况下
  18. 解决ftp 出现Passive mode refused的办法
  19. java 三点定位_GPS定位系统(三)——Java后端
  20. 软考分类精讲-计算机网络

热门文章

  1. IE浏览器安装zblog时,勾选了同意协议,下一步按钮呈现灰色状态不能点击的解决方法
  2. single-row subquery returns more than one row
  3. 51nod-2534 最小旅行路线
  4. 用java做出长方体的表面积_编写java程序,输入一个长方体的长、宽、高,求长方体的表面积和体积,并将结果显示,一个长方体的...
  5. 制作动态网站比较好用的软件工具
  6. java用代码实现星期菜谱_基于JAVA的菜谱大全接口调用代码实例
  7. Ubuntu 18.04安装openJDK7编译安卓6.0.0_r1
  8. ebs 选择excel输出 后缀 html,EBS报表输出文件格式控制
  9. 航海世纪服务器维护中,航海世纪2月28日例行维护公告
  10. 四种常用的100G QSFP28光模块的详细介绍