python爬取B站视频

参考:https://cloud.tencent.com/developer/article/1768680

参考的代码有点问题,请求头需要修改,上代码:

import requests
import re  # 正则表达式
import pprint
import json
from moviepy.editor import AudioFileClip, VideoFileClip
from bs4 import BeautifulSoup as bs

headers = {
    # 防盗链 告诉服务器 我们请求的url网址是从哪里跳转过来的
    'referer': 'https://www.bilibili.com/a',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
}

def send_request(url):
    response = requests.get(url=url, headers=headers)
    return response

def get_video_data(html_data):
    """解析视频数据"""

    # 提取视频的标题
    soup = bs(html_data, 'lxml')
    title = soup.find_all(name='h1',attrs={"class":"video-title special-text-indent"})[0].get_text()
    # print(title)

    # 提取视频对应的json数据
    json_data = re.findall('<script>window\.__playinfo__=(.*?)</script>', html_data)[0]
    # print(json_data)  # json_data 字符串
    json_data = json.loads(json_data)
    pprint.pprint(json_data)

    # 提取音频的url地址
    audio_url = json_data['data']['dash']['audio'][0]['backupUrl'][0]
    print('解析到的音频地址:', audio_url)

    # 提取视频画面的url地址
    video_url = json_data['data']['dash']['video'][0]['backupUrl'][0]
    print('解析到的视频地址:', video_url)

    video_data = [title, audio_url, video_url]
    return video_data

def save_data(file_name, audio_url, video_url):
    # 请求数据
    print('正在请求音频数据')
    audio_data = send_request(audio_url).content
    print('正在请求视频数据')
    video_data = send_request(video_url).content
    with open(file_name + '.mp3', mode='wb') as f:
        f.write(audio_data)
        print('正在保存音频数据')
    with open(file_name + '.mp4', mode='wb') as f:
        f.write(video_data)
        print('正在保存视频数据')

def merge_data(video_name):
    print('视频合成开始:', video_name)
    audioclip = AudioFileClip(video_name+'.mp3')
    videoclip = VideoFileClip(video_name+'.mp4')
    # 3.获取视频和音频的时长
    video_time = videoclip.duration
    audio_time = audioclip.duration
    # 4.对视频或者音频进行裁剪
    if video_time > audio_time:
        # 视频时长>音频时长,对视频进行截取
        videoclip_new = videoclip.subclip(0, audio_time)
        audioclip_new = audioclip
    else:
        # 音频时长>视频时长,对音频进行截取
        videoclip_new = videoclip
        audioclip_new = audioclip.subclip(0, video_time)
    # 5.视频中加入音频
    video_with_new_audio = videoclip_new.set_audio(audioclip_new)
    # 6.写入到新的视频文件中
    video_with_new_audio.write_videofile("output.mp4",
                                         codec='libx264',
                                         audio_codec='aac',
                                         temp_audiofile='temp-video.m4a',
                                         remove_temp=True
                                         )
    print('视频合成结束:', video_name)


url = 'https://www.bilibili.com/video/BV1bK421a7qG/?spm_id_from=333.1007.tianma.6-4-22.click'
response = send_request(url)
response.encoding = requests.utils.get_encodings_from_content(response.text)[0]
html_data = response.text
video_data = get_video_data(html_data)
save_data(video_data[0], video_data[1], video_data[2])
merge_data(video_data[0])

效果

小姐姐挺靓,就是左下角有水印,想办法去除水印,参考:python实战之去除视频水印&字幕_python 去除视频水印-CSDN博客

import os
import sys
import cv2
import numpy
from moviepy import editor
 
TEMP_VIDEO = 'temp.mp4'
 
 
class WatermarkRemover():
 
    def __init__(self, video_path, output, threshold: int, kernel_size: int):
        self.threshold = threshold  # 阈值分割所用阈值
        self.kernel_size = kernel_size  # 膨胀运算核尺寸
        self.video_path = video_path
        self.output = output
 
 
    #根据用户手动选择的ROI(Region of Interest,感兴趣区域)框选水印或字幕位置。
    def select_roi(self, img: numpy.ndarray, hint: str) -> list:
        '''
    框选水印或字幕位置,SPACE或ENTER键退出
    :param img: 显示图片
    :return: 框选区域坐标
    '''
        COFF = 0.7
        w, h = int(COFF * img.shape[1]), int(COFF * img.shape[0])
        resize_img = cv2.resize(img, (w, h))
        roi = cv2.selectROI(hint, resize_img, False, False)
        cv2.destroyAllWindows()
        watermark_roi = [int(roi[0] / COFF), int(roi[1] / COFF), int(roi[2] / COFF), int(roi[3] / COFF)]
        return watermark_roi
 
 
    #对输入的蒙版进行膨胀运算,扩大蒙版的范围
    def dilate_mask(self, mask: numpy.ndarray) -> numpy.ndarray:
 
        '''
    对蒙版进行膨胀运算
    :param mask: 蒙版图片
    :return: 膨胀处理后蒙版
    '''
        kernel = numpy.ones((self.kernel_size, self.kernel_size), numpy.uint8)
        mask = cv2.dilate(mask, kernel)
        return mask
    
    #根据手动选择的ROI区域,在单帧图像中生成水印或字幕的蒙版。
    def generate_single_mask(self, img: numpy.ndarray, roi: list, threshold: int) -> numpy.ndarray:
        '''
    通过手动选择的ROI区域生成单帧图像的水印蒙版
    :param img: 单帧图像
    :param roi: 手动选择区域坐标
    :param threshold: 二值化阈值
    :return: 水印蒙版
    '''
        # 区域无效,程序退出
        if len(roi) != 4:
            print('NULL ROI!')
            sys.exit()
 
        # 复制单帧灰度图像ROI内像素点
        roi_img = numpy.zeros((img.shape[0], img.shape[1]), numpy.uint8)
        start_x, end_x = int(roi[1]), int(roi[1] + roi[3])
        start_y, end_y = int(roi[0]), int(roi[0] + roi[2])
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        roi_img[start_x:end_x, start_y:end_y] = gray[start_x:end_x, start_y:end_y]
 
        # 阈值分割
        _, mask = cv2.threshold(roi_img, threshold, 255, cv2.THRESH_BINARY)
        return mask
 
    #通过截取视频中多帧图像生成多张水印蒙版,并通过逻辑与计算生成最终的水印蒙版
    def generate_watermark_mask(self, video_path: str) -> numpy.ndarray:
        '''
    截取视频中多帧图像生成多张水印蒙版,通过逻辑与计算生成最终水印蒙版
    :param video_path: 视频文件路径
    :return: 水印蒙版
    '''
        video = cv2.VideoCapture(video_path)
        success, frame = video.read()
        roi = self.select_roi(frame, 'select watermark ROI')
        mask = numpy.ones((frame.shape[0], frame.shape[1]), numpy.uint8)
        mask.fill(255)
 
        step = video.get(cv2.CAP_PROP_FRAME_COUNT) // 5
        index = 0
        while success:
            if index % step == 0:
                mask = cv2.bitwise_and(mask, self.generate_single_mask(frame, roi, self.threshold))
            success, frame = video.read()
            index += 1
        video.release()
 
        return self.dilate_mask(mask)
 
    #根据手动选择的ROI区域,在单帧图像中生成字幕的蒙版。
    def generate_subtitle_mask(self, frame: numpy.ndarray, roi: list) -> numpy.ndarray:
        '''
    通过手动选择ROI区域生成单帧图像字幕蒙版
    :param frame: 单帧图像
    :param roi: 手动选择区域坐标
    :return: 字幕蒙版
    '''
        mask = self.generate_single_mask(frame, [0, roi[1], frame.shape[1], roi[3]], self.threshold)  # 仅使用ROI横坐标区域
        return self.dilate_mask(mask)
 
    def inpaint_image(self, img: numpy.ndarray, mask: numpy.ndarray) -> numpy.ndarray:
        '''
    修复图像
    :param img: 单帧图像
    :parma mask: 蒙版
    :return: 修复后图像
    '''
        telea = cv2.inpaint(img, mask, 1, cv2.INPAINT_TELEA)
        return telea
 
 
    def merge_audio(self, input_path: str, output_path: str, temp_path: str):
        '''
    合并音频与处理后视频
    :param input_path: 原视频文件路径
    :param output_path: 封装音视频后文件路径
    :param temp_path: 无声视频文件路径
    '''
        with editor.VideoFileClip(input_path) as video:
            audio = video.audio
            with editor.VideoFileClip(temp_path) as opencv_video:
                clip = opencv_video.set_audio(audio)
                clip.to_videofile(output_path)
 
    def remove_video_watermark(self):
        '''
    去除视频水印
    '''
        if not os.path.exists(self.output):
            os.makedirs(self.output)
 
        filenames = [os.path.join(self.video_path, i) for i in os.listdir(self.video_path)]
        mask = None
 
        for i, name in enumerate(filenames):
            if i == 0:
                # 生成水印蒙版
                mask = self.generate_watermark_mask(name)
 
            # 创建待写入文件对象
            video = cv2.VideoCapture(name)
            fps = video.get(cv2.CAP_PROP_FPS)
            size = (int(video.get(cv2.CAP_PROP_FRAME_WIDTH)), int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)))
            video_writer = cv2.VideoWriter(TEMP_VIDEO, cv2.VideoWriter_fourcc(*'mp4v'), fps, size)
 
            # 逐帧处理图像
            success, frame = video.read()
 
            while success:
                frame = self.inpaint_image(frame, mask)
                video_writer.write(frame)
                success, frame = video.read()
 
            video.release()
            video_writer.release()
 
            # 封装视频
            (_, filename) = os.path.split(name)
            output_path = os.path.join(self.output, filename.split('.')[0] + '_no_watermark.mp4')  # 输出文件路径
            self.merge_audio(name, output_path, TEMP_VIDEO)
 
    if os.path.exists(TEMP_VIDEO):
        os.remove(TEMP_VIDEO)
 
    def remove_video_subtitle(self):
        '''去除视频字幕'''
        if not os.path.exists(self.output):
            os.makedirs(self.output)
 
        filenames = [os.path.join(self.video_path, i) for i in os.listdir(self.video_path)]
        roi = []
 
        for i, name in enumerate(filenames):
            # 创建待写入文件对象
            video = cv2.VideoCapture(name)
            fps = video.get(cv2.CAP_PROP_FPS)
            size = (int(video.get(cv2.CAP_PROP_FRAME_WIDTH)), int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)))
            video_writer = cv2.VideoWriter(TEMP_VIDEO, cv2.VideoWriter_fourcc(*'mp4v'), fps, size)
 
            # 逐帧处理图像
            success, frame = video.read()
            if i == 0:
                roi = self.select_roi(frame, 'select subtitle ROI')
 
            while success:
                mask = self.generate_subtitle_mask(frame, roi)
                frame = self.inpaint_image(frame, mask)
                video_writer.write(frame)
                success, frame = video.read()
 
            video.release()
            video_writer.release()
 
            # 封装视频
            (_, filename) = os.path.split(name)
            output_path = os.path.join(OUTPUT_PATH, filename.split('.')[0] + '_no_sub.mp4')  # 输出文件路径
            self.merge_audio(name, output_path, TEMP_VIDEO)
 
        if os.path.exists(TEMP_VIDEO):
            os.remove(TEMP_VIDEO)
 
 # 去水印
video_path = 'video'
output_path = 'output'
remover = WatermarkRemover(video_path,output_path,threshold=80, kernel_size=5)
remover.remove_video_watermark()   
#去字幕
# remover = WatermarkRemover(video_path,output_path,threshold=80, kernel_size=5)
# remover.remove_video_subtitle()

效果一般吧:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/505869.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QT初识(2)

QT初识&#xff08;2&#xff09; 创建好项目之后&#xff0c;多了些什么东西&#xff1f;main.cppwidget.hwidget.cppwidget.ui.pro项目工程文件 我们今天来继续了解QT。如果没看过上一次QT初识的小伙伴可以点击这里&#xff1a; https://blog.csdn.net/qq_67693066/article/d…

STM32的DMA

DMA(Direct memory access)直接存储器存取,用来提供在外设和存储器之间或者存储 器和存储器之间的高速数据传输&#xff0c;无须CPU干预&#xff0c;数据可以通过DMA快速地移动&#xff0c;这就节 省了CPU的资源来做其他操作。 STM32有两个DMA控制器共12个通道(DMA1有7个通道…

基于YOLOV8+Pyqt5光伏太阳能电池板目标检测系统

1、YOLOV8算法 YOLOv8 是当前效果较好的目标检测 算法&#xff0c;它的核心网络来源于 DarkNet-53&#xff0c;该网络初次在 YOLOv3[11] 中被引入&#xff0c;并深受 ResNet[12] 的影响。DarkNet-53 使用了残差机制&#xff0c;并连续添加了卷积模块来加强其功能性。 这 53 层…

Cortex‐M3/M4/M7内核的操作模式和特权等级介绍

0 前言 如果我们是基于MCU的裸机编程&#xff0c;是不需要关心内核的操作模式和特权等级的。如果是进行RTOS的开发编程&#xff0c;我们就要必要了解一下Cortex‐M3/M4/M7内核的操作模式和特权等级&#xff0c;这在RTOS的线程切换等场合会使用到。 1 Cortex‐M3/M4/M7内核的操…

栈————顺序栈和链式栈

目录 栈 顺序栈 1、初始化顺序栈 2、判栈空 3、进栈 4、出栈 5、读栈顶元素 6、遍历 链式栈 1、初始化链式栈 2、断链式栈是否为空判 3、入栈(插入) ​编辑​编辑 4、出栈(删除) 5、读取栈顶元素 6、输出链式栈中各个节点的值&#xff08;遍历&#xff09; 栈 …

Golang | Leetcode Golang题解之第2题两数相加

题目&#xff1a; 题解&#xff1a; func addTwoNumbers(l1, l2 *ListNode) (head *ListNode) {var tail *ListNodecarry : 0for l1 ! nil || l2 ! nil {n1, n2 : 0, 0if l1 ! nil {n1 l1.Vall1 l1.Next}if l2 ! nil {n2 l2.Vall2 l2.Next}sum : n1 n2 carrysum, carry …

(React组件基础)前端八股文Day6

一 类组件与函数组件有什么异同 在React中&#xff0c;类组件和函数组件是创建组件的两种主要方式。随着React的发展&#xff0c;尤其是自Hooks在React 16.8中引入以来&#xff0c;函数组件的功能变得更加强大&#xff0c;使得它们能够更加方便地与类组件相竞争。下面是类组件…

MySQL数据库(高级)

文章目录 1.MySQL约束1.主键细节说明演示复合主键 2.not null&#xff08;非空&#xff09;3.unique&#xff08;唯一&#xff09;细节说明演示 4.外键外键示意图使用细节演示 5.check演示 6.创建表练习答案 7.自增长演示细节 2.索引1.索引机制2.创建索引演示细节 3.删除索引4.…

【苹果MAC】苹果电脑 LOGI罗技鼠标设置左右切换全屏页面快捷键

首先键盘设置->键盘快捷键 调度中心 设置 f1 f2 为移动一个空间&#xff08;就可以快捷移动了&#xff09; 想要鼠标直接控制&#xff0c;就需要下载官方驱动&#xff0c;来设置按键快捷键&#xff0c;触发 F1 F2 安装 LOGI OPTIONS Logi Options 是一款功能强大且便于使用…

Yarn的安装和使用(2):使用及问题解决

Yarn是JavaScript的依赖管理工具&#xff0c;它与npm类似&#xff0c;但提供了一些额外的性能优化和一致性保证。 Yarn的使用&#xff1a; 初始化项目&#xff1a; yarn init 此命令会引导您创建一个新的package.json文件&#xff0c;用于记录项目的元信息和依赖。 添加依赖&…

38.HarmonyOS鸿蒙系统 App(ArkUI)堆叠布局结合弹性布局

层叠布局用于在屏幕上预留一块区域来显示组件中的元素&#xff0c;提供元素可以重叠的布局。层叠布局通过Stack容器组件实现位置的固定定位与层叠&#xff0c;容器中的子元素&#xff08;子组件&#xff09;依次入栈&#xff0c;后一个子元素覆盖前一个子元素&#xff0c;子元素…

神经网络与深度学习(一)误差反传BP算法

误差反传BP算法 1多层感知机1.1XOR问题1.2多层感知机 2.BP算法2.1简述2.2详解2.2.1输入输出模型2.2.2梯度下降算法迭代2.2.3前向传播在输出端计算误差2.2.4误差反传--输出层2.2.5误差反传--隐含层2.2.6误差反传--总结 1多层感知机 1.1XOR问题 线性不可分问题&#xff1a; 无法…

正弦实时数据库(SinRTDB)的使用(10)-数据文件的无损压缩

前文已经将正弦实时数据库的使用进行了介绍&#xff0c;需要了解的可以先看下面的博客&#xff1a; 正弦实时数据库(SinRTDB)的安装 正弦实时数据库(SinRTDB)的使用(1)-使用数据发生器写入数据 正弦实时数据库(SinRTDB)的使用(2)-接入OPC DA的数据 正弦实时数据库(SinRTDB)…

LabVIEW双通道太阳射电频谱观测系统

LabVIEW双通道太阳射电频谱观测系统 开发了一个基于LabVIEW平台开发的双通道高速太阳射电频谱观测系统。该系统实时监测太阳射电爆发&#xff0c;具有随机性、持续时间短、变化快等特点。通过高速信号采集卡实现1.5 GS/s的信号采集&#xff0c;时间分辨率可达4ms&#xff0c;频…

jvm类加载机制概述

、什么是jvm的类加载机制 类加载机制是指我们将类的字节码文件所包含的数据读入内存&#xff0c;同时我们会生成数据的访问入口的一种 特殊机制。那么我们可以得知&#xff0c;类加载的最终产品是数据访问入口。 加载类文件&#xff08;即.class文件&#xff09;的方式有以下几…

ChatGPT chrome扩展下载与安装

官方下载地址 https://chromewebstore.google.com/detail/lpbhmlbicmgjpacbofijdfpcplfhakeo 截图 安装 离线安装 下载地址 https://static.xutongbao.top/app/chatgpt-chrome-crx-v0.0.7.zip 打开链接 chrome://extensions/ 人工智能学习网站 https://chat.xutongbao.to…

获取电商数据的几种方法分享

在数字化时代&#xff0c;电商数据已经成为企业决策的重要依据。无论是市场趋势的洞察、用户行为的分析&#xff0c;还是产品优化和营销策略的制定&#xff0c;都离不开电商数据的支持。本文将分享几种获取电商数据的有效方法&#xff0c;力求在干货满满的同时&#xff0c;也不…

精通【PHP循环结构知识】

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

怎么打包出release.aar包

第一种 选择build variant 更改成release 第二钟 在gradle中选择相应任务来编译 选择assemble release如果没有这个选项&#xff0c;可能是你没有开启那个Task 收集的选项

Acrobat Pro DC 2023 for Mac PDF编辑管理软件

Acrobat Pro DC 2023 for Mac是一款功能强大的PDF编辑和管理软件&#xff0c;旨在帮助用户轻松处理PDF文件。它提供了丰富的工具和功能&#xff0c;使用户可以创建、编辑、转换和注释PDF文件&#xff0c;以及填写和签署PDF表单。 软件下载&#xff1a;Acrobat Pro DC 2023 for …