python爬虫获取vip视频犯法吗 (python爬虫哔哩哔哩)

观前注意事项:本文极其粗略晦涩,不适合毫无编程基础的新手阅读浏览(用于助眠除外),建议阅读者在通过全国计算机二级python考试后(哪怕是擦边的60分)再来阅览,并且该文思路方法具有相当的局限性,仅适用于相当少一部分的哔哩哔哩网站非大会员且非付费观看的视频,敬请酌情参考使用。

==================================================================

哔哩哔哩(Bilibili)是中国年轻一代的标志性平台以及领先的视频社区,在这一粉色世界里,玩家将扮演手持硬币的Up主(或游客)观赏品鉴他人的影视作品,并选择打赏或白嫖,而白嫖是一门颇有学问的寝取行为……嗯?白嫖能有什么深度可探索?不投币,不点赞,不转发,看完视频,下次丕定不就得了,还能有什么门道?哦,只可惜,你看完视频的时候无论再怎么吝啬你还是为视频发布者贡献了一份*放播**量。

python爬虫哔哩哔哩,python爬虫获取vip音乐

阳谋:你不看,就没办法白嫖;你看了,就*放播**量+1

为了能够以更为恶劣的手段来享[bái]受[piáo]Up主的影视作品,本文介绍了一种基于python的爬虫构建方法,以期能够达到在不打开哔哩哔哩视频所在网页端提前加载的情况下品[bái]鉴[piáo]个人感兴趣视频的最终效果。

本文涉及计算机系统为Windows 11 版本22H2(OS 内部版本22621.2715),所用python版本为3.10.6 (tags/v3.10.6:9c7b4bd, Aug 1 2022, 21:53:49) [MSC v.1932 64 bit (AMD64)],示例浏览器为Google Chrome121.0.6167.162 (正式版本) (64 位),涉及到的python库有:requests, BeautifulSoup4, subprocess, 演示所用代码编译器为Visual Studio Code version 1.71.0。

场景模拟:

你叫李华,你大洋彼岸的好朋友杰哥想要在平板无网络且不*载下**Bilibili应用软件的条件下反复回味idol蔡徐坤历练一坤年的出道首秀。请你按照给定的高清视频BV号BV1ct4y1n7t9,为杰哥端上《只因你太美》的1080P离线缓存视频文件。

为方便浏览,本文大致分为以下两个模块:

0)地址解析

1)音视保存

2)文件处理

==================================================================

0 地址解析

打开目标网站https://www.bilibili.com/video/BV1ct4y1n7t9,直接F12检查网页,将所有加载选项清空一遍后重新加载网页

python爬虫哔哩哔哩,python爬虫获取vip音乐

可以看到浏览器在刚进入这个网页进行视频*放播**前,浏览器会预先加载两份高度嫌疑文件

python爬虫哔哩哔哩,python爬虫获取vip音乐

点击查看一下浏览器请求的源文件地址

python爬虫哔哩哔哩,python爬虫获取vip音乐

可以看到这个文件的真实网址是一坨,看不懂,但还好不需要看懂,两个文件的源网址都确认一下之后,不难发现,网址组成给人的主观感觉是:

https:// 锟斤拷锟斤拷锟斤拷锟斤拷/NNN-N-100026.m4s? 锟斤拷锟斤拷锟斤拷锟斤拷…

https:// 锟斤拷锟斤拷锟斤拷锟斤拷/NNN-N-30280.m4s? 锟斤拷锟斤拷锟斤拷锟斤拷…

很明显的其实就是网页预先加载了两份后缀为.m4s的文件。辣么为什么这后缀.m4s的文件会引起我们的警♂觉呢?只要看一下.m4s文件的定义,便可略知一二

python爬虫哔哩哔哩,python爬虫获取vip音乐

由此看来[.m4s]后缀的文件有相当的概率就是我们所寻找的视频本身,那么接下来就康康这m4s文件的地址在原网页能不能直接找到,还是https://www.bilibili.com/video/BV1ct4y1n7t9这个网页,只不过这次点进去之后直接Ctrl+U产看网页的源码

python爬虫哔哩哔哩,python爬虫获取vip音乐

然后直接Ctrl+F(或者鼠标右键搜索)100026.m4s

python爬虫哔哩哔哩,python爬虫获取vip音乐

可以看到,首号嫌疑文件100026.m4s的源地址是直接就挂在网页源码上的,那么我们就逝逝用python爬虫把这个文件地址先提取出来,再尝试爬取

python爬虫哔哩哔哩,python爬虫获取vip音乐

稍微往上头看一下,不难发现100026.m4s的源文件地址是储存在<script>的元素中的,而在这个网页*共中**有19个<script>元素,我们要的m4s文件源地址在从上往下数第四个<script>元素里

python爬虫哔哩哔哩,python爬虫获取vip音乐

直接上python代码,试着把所有<script>元素爬取下来看看内容,比对确认一下

import requests

from bs4 import BeautifulSoup #导入所需库

response = requests . get ( 'https://www.bilibili.com/video/BV1ct4y1n7t9' ) #发起网页请求

beso = BeautifulSoup ( response . text , 'html.parser' ) #将网址源码转换为BeautifulSoup对象

info_list = beso . find_all ( 'script' ) #找到所有<script>元素并按顺序逐一展示

for info in info_list :

print ( info )

然后惊喜的寄了,输出内容根本没有包含目标m4s地址

python爬虫哔哩哔哩,python爬虫获取vip音乐

那就先看下请求的响应状态

response = requests . get ( 'https://www.bilibili.com/video/BV1ct4y1n7t9' )

print ( response . status_code )

果不其然,显示为异常代码412,状态码412含义为:Precondition Failed,服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。这个状态码允许客户端在获取资源时在请求的元信息(请求头字段数据)中设置先决条件,以此避免该请求方法被应用到其希望的内容以外的资源上。

python爬虫哔哩哔哩,python爬虫获取vip音乐

那就看一下网页请求里面的Request Headers(请求头)的构成

python爬虫哔哩哔哩,python爬虫获取vip音乐

把这里面一坨信息反复增添删减实验之后,发现在构建的请求头中保留‘user-agent’, ‘Referer’这两份信息基本就能润过412

header0 = {

'user-agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36' ,

'Referer' : 'https://search.bilibili.com/'

}

response = requests . get ( 'https://www.bilibili.com/video/BV1ct4y1n7t9' , headers = header0 )

print ( response . status_code )

再次运行代码,查看请求的响应状态,是喜人的200

python爬虫哔哩哔哩,python爬虫获取vip音乐

辣么一切照旧,在有请求头的情况下再爬取一遍所有的<script>元素

response = requests . get ( 'https://www.bilibili.com/video/BV1ct4y1n7t9' , headers = header0 )

beso = BeautifulSoup ( response . text , 'html.parser' )

info_list = beso . find_all ( 'script' )

for info in info_list :

print ( info )

可以看到,这次终端输出的<script>元素里包含了我们所需要的m4s文件源地址信息

python爬虫哔哩哔哩,python爬虫获取vip音乐

而且这个信息在第4顺位的<script>中,跑个码验证一下,python中list计数是从0记起的,所以是列表里的“第3个”成分

response = requests . get ( 'https://www.bilibili.com/video/BV1ct4y1n7t9' , headers = header0 )

beso = BeautifulSoup ( response . text , 'html.parser' )

info_list = beso . find_all ( 'script' )

print ( info_list [ 3 ])

终端输出结果印证,确实没错

python爬虫哔哩哔哩,python爬虫获取vip音乐

那接下来就是要从这个<script>的一坨文本里头提取出m4s文件地址了,乍一看这一堆文本琐碎至极,直叫人脑壳发痛,但是笼统的看下来还是有点规律的,其实就是很典型的字典嵌套字典嵌套字典嵌套列表再嵌套字典的超级套娃结构

python爬虫哔哩哔哩,python爬虫获取vip音乐

这就相当于名为“window.__playinfo”的这个超大大字典里有名为“data“这个大字典,而后者又包含有名为“dash”这个中字典,而“dash”字典又包含有名为“video”的超大列表,而这名为“video”超大列表的“第0个”组成元素又是一个字典,而这最终的字典里面名为“baseUrl”的“键”所对应的“值”即是我们所探求的m4s文件源地址。

python爬虫哔哩哔哩,python爬虫获取vip音乐

搞清楚层级包含关系之后,要提取信息就相对有头绪了,但是当你主动打开一扇门,上天会给你被动地关上一扇窗,我们先来康康我们之前提取出来的信息的类别

response = requests . get ( 'https://www.bilibili.com/video/BV1ct4y1n7t9' , headers = header0 )

beso = BeautifulSoup ( response . text , 'html.parser' )

info_list = beso . find_all ( 'script' )

print ( type ( info_list [ 3 ]))

输出之后可以看到结果是<class 'bs4.element.Tag'>,并不是’dict’或者是’list‘,所以不能直接按照字典或者列表的方式调用内部组成元素,不过倒是能够添加“.text”后缀将这一坨信息提取转换为文本字符串

response = requests . get ( 'https://www.bilibili.com/video/BV1ct4y1n7t9' , headers = header0 )

beso = BeautifulSoup ( response . text , 'html.parser' )

info_list = beso . find_all ( 'script' )

print ( type ( info_list [ 3 ].text))

终端输出结果也印证了这一点

python爬虫哔哩哔哩,python爬虫获取vip音乐

辣么问题又TM来了,字符串是字符串,字典是字典,还是不能够直接以调用字典键-值的形式直接处理这一坨字符串,但是我们要的m4s文件源地址又在这一坨里头,肿么办呢?有没有什么方法能够将按照字典结构排列的字符串转化为字典呢?

偷懒是人类进步的久动机,确实存在这么一个方法:eval()

python爬虫哔哩哔哩,python爬虫获取vip音乐

看不懂也没有太大关系,只需要知道这个函数能达到我们的字典转化目的就可以了,下面简单的看下实操代码

response = requests . get ( 'https://www.bilibili.com/video/BV1ct4y1n7t9' , headers = header0 )

beso = BeautifulSoup ( response . text , 'html.parser' )

info_list = beso . find_all ( 'script' )

information = eval ( info_list [ 3 ].text.strip( 'window.__playinfo__=' )) #将<script>元素内的信息转化为str类型的字符串后,再用strip()函数去掉多余的字符,最后eval()函数收尾将整体转化为字典

print ( information )

然鹅……

python爬虫哔哩哔哩,python爬虫获取vip音乐

看了一下,就是eval()函数所在这一行出错了,错误内容是有一个从未被定义的变量”null”存在,程序无法识别,看了下网页源码,变量”null”确实存在

python爬虫哔哩哔哩,python爬虫获取vip音乐

这里有一个鸡贼且取巧的解决方案,我们可以在eval()函数之前提前给null随意赋值,具体定义如何可各自发挥,“null”变量只是个摆设,并不重要

null = None

response = requests . get ( 'https://www.bilibili.com/video/BV1ct4y1n7t9' , headers = header0 )

beso = BeautifulSoup ( response . text , 'html.parser' )

info_list = beso . find_all ( 'script' )

information = eval ( info_list [ 3 ].text.strip( 'window.__playinfo__=' )) #将<script>元素内的信息转化为str类型的字符串后,再用strip()函数去掉多余的字符,最后eval()函数收尾将整体转化为字典,并且赋值给新变量“information”

print ( information ) #显示出来康康

print ( type ( information )) #确认一下变量information的类型

这一次输出结果总算对味了,虽然表面上看起来组成信息的字幕都是一样的,但是组成的信息本身的类型却已经发生了质的变化

python爬虫哔哩哔哩,python爬虫获取vip音乐

Information类型显示为’dict’——字典,可以运用字典的方式调用内部组成的键和值了,结合一下上面的示意图所展现的信息包含层级,稍微捋一捋

null = None

response = requests . get ( 'https://www.bilibili.com/video/BV1ct4y1n7t9' , headers = header0 )

beso = BeautifulSoup ( response . text , 'html.parser' )

info_list = beso . find_all ( 'script' )

information = eval ( info_list [ 3 ].text.strip( 'window.__playinfo__=' )) #将<script>元素内的信息转化为str类型的字符串后,再用strip()函数去掉多余的字符,最后eval()函数收尾将整体转化为字典

print ( information [ 'data' ][ 'dash' ][ 'video' ][ 0 ][ 'baseUrl' ]) #提取m4s文件地址,具体构成看上面的层级图,这里太窄,解释不清

可以欣慰的看到,这一坨m4s文件源地址总算是从这一大坨网页源码里面被我们提出来了,真是粪坑拉细便——又臭又长

python爬虫哔哩哔哩,python爬虫获取vip音乐

那么包含我们想要的视频文件.m4s源地址解析出来了,接下来就进入下一大步,文件的*载下**储存部分。