Python爬虫实战:利用代理IP批量下载哔哩哔哩美女视频

news2024/11/19 2:24:00

文章 目录

  • 1.前言
  • 2.爬取目标
  • 3.准备工作
    • 3.1 环境安装
    • 3.2 代理免费获取
  • 四、爬虫实战分析
    • 4.1 翻页分析
    • 4.2 获取视频跳转链接
    • 4.3 下载视频
    • 4.4 视频音频合并
    • 4.5 完整源码
  • 五、总结

1.前言

粉丝们(lsp)期待已久的Python批量下载哔哩哔哩美女视频教程它终于来了,接下来跟着我的步骤一步步实现即可!

2.爬取目标

本次博主爬取的目标是哔哩哔哩在搜索框输入关键词后的所有视频:

3.准备工作

3.1 环境安装

Python:3.10

编辑器:PyCharm

由于哔哩哔哩的视频和音频是分开的,所以本次我们需要用到moviepy模块进行合并(moviepy 是一个强大的 Python 模块,用于视频编辑,如视频剪辑、视频合成、视频字幕添加、音频处理等),执行下面pip命令进行安装:

pip install requests # 网页数据爬取
pip install moviepy # 用于合并音频和视频

3.2 代理免费获取

由于哔哩哔哩限制很严,为了能正常获取数据,博主使用了代理IP。

1、注册账号:代理IP试用

2、选择查看代理IP产品:

3、有动态IP、静态IP、机房IP、移动代理IP可以选择,博主这里选择是机房IP:

4、配置通道,可以设置IP类型(共享/独享)、IP数、IP来源国家等等:

5、配置完成后可以看到主机、用户名和密码,等下我们添加到代码中去获取IP:

6、下面代码只需要修改刚才获取到的主机、用户名和密码,即可返回代理IP:

import requests  # python基础爬虫库


def get_ip():
    """获取亮数据代理IP"""
    host = '你的主机' # 主机
    user_name = '你的用户名' # 用户名
    password = '你的密码' # 密码

    proxy_url = f'http://{user_name}:{password}@{host}' # 将上面三个参数拼接为专属代理IP获取网址
    proxies = {
        'http':proxy_url,
        'https':proxy_url
    }

    url = "http://lumtest.com/myip.json" # 默认获取的接口(不用修改)
    response = requests.get(url,proxies=proxies,timeout=10).text # 发送请求获取IP
    # print('代理IP详情信息:',response)
    response_dict = eval(response)  # 将字符串转为字典,方便我们提取代理IP
    ip =  response_dict['ip']
    # print('IP:',ip)
    return ip


get_ip()

成功返回IP获取成功:

四、爬虫实战分析

4.1 翻页分析

我们搜索关键词后翻页看看链接的规律如下:

第一页链接:

https://search.bilibili.com/all?keyword=%E7%BE%8E%E5%A5%B3%E8%B7%B3%E8%88%9E&from_source=webtop_search&search_source=5

第二页链接:

https://search.bilibili.com/all?vt=67815047&keyword=%E7%BE%8E%E5%A5%B3%E8%B7%B3%E8%88%9E&from_source=webtop_search&search_source=5&page=1&o=30

第三页链接:

https://search.bilibili.com/all?keyword=%E7%BE%8E%E5%A5%B3%E8%B7%B3%E8%88%9E&from_source=webtop_search&search_source=5&page=3&o=60

第四页链接:

https://search.bilibili.com/all?keyword=%E7%BE%8E%E5%A5%B3%E8%B7%B3%E8%88%9E&from_source=webtop_search&search_source=5&page=4&o=90

由上面可以看出规律,我们只需要传入keyword、page和o参数即可:

def main():
    keyword = '美女跳舞'  # 搜索的关键词
    page = 1  # 爬取的页数(每页30个视频)
    jump_url_list = [] # 用于存放搜索页每页的全部视频跳转链接
    for i in range(1,page+1):
        if i ==1:
            url = f'https://search.bilibili.com/all?keyword={keyword}&from_source=webtop_search&search_source=5'
        else:
            url = f'https://search.bilibili.com/all?keyword={keyword}&from_source=webtop_search&search_source=5&page={i-1}&o={(i-1)*30}'
        print(url)

4.2 获取视频跳转链接

1、可以看到所有视频都在一个div下面:

2、然后找到我们要的跳转链接,可以看到在一个a标签下:

3、接下来只需要获取每一个视频跳转链接即可:

def get_jump_url(url,jump_url_list):
    """获取视频跳转链接"""
    headers = {
        'Accept': '*/*',
        'Accept-Language': 'en-US,en;q=0.5',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
    }
    # 发送请求
    response = requests.get(url, headers=headers)
    # 获取网页源码
    html_str = response.content.decode()
    # print(html_str)
    html_data = etree.HTML(html_str)
    # 利用xpath取到所有的li标签
    div_list = html_data.xpath("//div[@class='video-list row']/div")
    # 打印一下div标签个数
    # print(len(div_list))
    for div in div_list:
        # 拼接跳转链接
        jump_url = 'https:'+div.xpath(".//div[@class='bili-video-card__wrap __scale-wrap']/a/@href")[0]
        # print(jump_url)
        # 这里限制一下我们需要的跳转链接,排除无用的链接
        if 'https://www.bilibili.com/video' in jump_url:
            # 跳转链接存放在列表中
            jump_url_list.append(jump_url)

5、获取成功检查一下跳转链接是否正常跳转:

没有问题正常打开:

4.3 下载视频

1、首先先找到标题所在标签:

2、视频和音频都藏在script标签里面:

3、遍历我们刚才的跳转链接列表取一个链接进行测试:

def download_video(jump_url_list,keyword):
    # 遍历我们刚才获取到的所有跳转链接
    for jump_url in jump_url_list: # 先取一个视频进行测试
        print('正在下载:',jump_url)
        # 发送请求
        headers = {
            'Accept': '*/*',
            'Accept-Language': 'en-US,en;q=0.5',
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
        }
        # 添加代理IP(这里代理IP这里需要看`3.2 获取代理IP`自己去获取)
        proxies = get_ip()
        response = requests.get(jump_url, headers=headers, proxies=proxies)
        # 视频详情json
        match = re.search( '__playinfo__=(.*?)</script><script>',response.text)
        playinfo =  json.loads(match.group(1))

        # 视频内容json
        match = re.search( r'__INITIAL_STATE__=(.*?);\(function\(\)',response.text)
        initial_state = json.loads(match.group(1))

        # 视频分多种格式,直接取分辨率最高的视频 1080p
        video_url = playinfo['data']['dash']['video'][0]['baseUrl']
        # 取出音频地址
        audio_url = playinfo['data']['dash']['audio'][0]['baseUrl']
        title = initial_state['videoData']['title']
        print('视频名字:',title)
        # print('视频地址:', video_url)
        # print('音频地址:', audio_url)

        # 根据关键词创建文件夹
        if not os.path.exists(keyword):
            os.mkdir(keyword)

        # 下载视频
        headers.update({"Referer": jump_url})
        video_content = requests.get(video_url, headers=headers)
        received_video = 0
        video_path = f'./{keyword}/{title}_video.mp4'
        with open(video_path, 'ab') as output:
            while int(video_content.headers['content-length']) > received_video:
                headers['Range'] = 'bytes=' + str(received_video) + '-'
                response = requests.get(video_url, headers=headers)
                output.write(response.content)
                received_video += len(response.content)

        # 下载音频
        audio_content = requests.get(audio_url, headers=headers)
        received_audio = 0
        audio_path = f'./{keyword}/{title}_audio.mp4'
        with open(audio_path, 'ab') as output:
            while int(audio_content.headers['content-length']) > received_audio:
                # 视频分片下载
                headers['Range'] = 'bytes=' + str(received_audio) + '-'
                response = requests.get(audio_url, headers=headers)
                output.write(response.content)
                received_audio += len(response.content)

生成指定关键词文件夹,并下载成功视频和音频:

4.4 视频音频合并

这里我们定义一个合并函数,需要传入视频和音频路径即可(注意:合并可能有点慢请耐心等待即可):

def merge_video_audio(video_path, audio_path):
    """传入原始视频和音频路径,合并为新的视频,并删除原始视频和音频"""
    print('视频视频合并中请耐心等待~')
    # 获取下载好的音频和视频文件
    vd = VideoFileClip(video_path)
    ad = AudioFileClip(audio_path)
    vd2 = vd.set_audio(ad)  # 将提取到的音频和视频文件进行合成
    output = video_path.replace('_video','')
    vd2.write_videofile(output)  # 输出新的视频文件

    # 移除原始的视频和音频
    os.remove(video_path)
    os.remove(audio_path)

合并中:

合并成功并删除原始的视频和音频:

4.5 完整源码

下面完整代码需要看3.2获取 并 修改get_ip()函数中的 代理IP信息(主机、用户名和密码),还可以修改关键词和爬取的页数:

import time
import requests
import json
import re
from lxml import etree
from moviepy.editor import *


def get_ip():
    """获取亮数据代理IP"""
    host = '你的主机'  # 主机
    user_name = '你的用户名'  # 用户名
    password = '你的密码'  # 密码

    proxy_url = f'http://{user_name}:{password}@{host}'  # 将上面三个参数拼接为专属代理IP获取网址
    proxies = {
        'http': proxy_url,
        'https': proxy_url
    }

    url = "http://lumtest.com/myip.json"  # 默认获取的接口(不用修改)
    response = requests.get(url, proxies=proxies, timeout=10).text  # 发送请求获取IP
    # print('代理IP详情信息:',response)
    response_dict = eval(response)  # 将字符串转为字典,方便我们提取代理IP
    ip = response_dict['ip']
    # print('IP:',ip)
    return ip


def get_jump_url(url,jump_url_list):
    """获取视频跳转链接"""
    headers = {
        'Accept': '*/*',
        'Accept-Language': 'en-US,en;q=0.5',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
    }
    # 发送请求
    response = requests.get(url, headers=headers)
    # 获取网页源码
    html_str = response.content.decode()
    # print(html_str)
    html_data = etree.HTML(html_str)
    # 利用xpath取到所有的li标签
    div_list = html_data.xpath("//div[@class='video-list row']/div")
    # 打印一下div标签个数
    # print(len(div_list))
    for div in div_list:
        # 拼接跳转链接
        jump_url = 'https:'+div.xpath(".//div[@class='bili-video-card__wrap __scale-wrap']/a/@href")[0]
        # print(jump_url)
        # 这里限制一下我们需要的跳转链接,排除无用的链接
        if 'https://www.bilibili.com/video' in jump_url:
            # 跳转链接存放在列表中
            jump_url_list.append(jump_url)


def merge_video_audio(video_path, audio_path):
    """传入原始视频和音频路径,合并为新的视频,并删除原始视频和音频"""
    print('原始视频音频合并中,请耐心等待~')
    # 获取下载好的音频和视频文件
    vd = VideoFileClip(video_path)
    ad = AudioFileClip(audio_path)
    vd2 = vd.set_audio(ad)  # 将提取到的音频和视频文件进行合成
    output = video_path.replace('_video','')
    vd2.write_videofile(output)  # 输出新的视频文件

    # 移除原始的视频和音频
    os.remove(video_path)
    os.remove(audio_path)


def download_video(jump_url_list,keyword):
    # 遍历我们刚才获取到的所有跳转链接
    for jump_url in jump_url_list: # 先取一个视频进行测试
        print('正在下载:',jump_url)
        # 发送请求
        headers = {
            'Accept': '*/*',
            'Accept-Language': 'en-US,en;q=0.5',
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
        }
        # 添加代理IP(这里代理IP这里需要看`3.2 获取代理IP`自己去获取)
        proxies = get_ip()
        response = requests.get(jump_url, headers=headers, proxies=proxies)
        # 视频详情json
        match = re.search( '__playinfo__=(.*?)</script><script>',response.text)
        playinfo =  json.loads(match.group(1))

        # 视频内容json
        match = re.search( r'__INITIAL_STATE__=(.*?);\(function\(\)',response.text)
        initial_state = json.loads(match.group(1))

        # 视频分多种格式,直接取分辨率最高的视频 1080p
        video_url = playinfo['data']['dash']['video'][0]['baseUrl']
        # 取出音频地址
        audio_url = playinfo['data']['dash']['audio'][0]['baseUrl']
        title = initial_state['videoData']['title']
        print('视频名字:',title)
        # print('视频地址:', video_url)
        # print('音频地址:', audio_url)

        # 根据关键词创建文件夹
        if not os.path.exists(keyword):
            os.mkdir(keyword)

        # 下载视频
        headers.update({"Referer": jump_url})
        video_content = requests.get(video_url, headers=headers)
        received_video = 0
        video_path = f'./{keyword}/{title}_video.mp4'
        with open(video_path, 'ab') as output:
            while int(video_content.headers['content-length']) > received_video:
                headers['Range'] = 'bytes=' + str(received_video) + '-'
                response = requests.get(video_url, headers=headers)
                output.write(response.content)
                received_video += len(response.content)

        # 下载音频
        audio_content = requests.get(audio_url, headers=headers)
        received_audio = 0
        audio_path = f'./{keyword}/{title}_audio.mp4'
        with open(audio_path, 'ab') as output:
            while int(audio_content.headers['content-length']) > received_audio:
                # 视频分片下载
                headers['Range'] = 'bytes=' + str(received_audio) + '-'
                response = requests.get(audio_url, headers=headers)
                output.write(response.content)
                received_audio += len(response.content)

        # 合并视频和音频
        merge_video_audio(video_path, audio_path)
        print('********************这是一条隔离线***************************')

        time.sleep(1)  # 限制速度不能太快了,如果还是不行继续增加暂停时间


def main():
    keyword = '美女跳舞'  # 搜索的关键词
    page = 1  # 爬取的页数(每页30个视频)
    jump_url_list = [] # 用于存放搜索页每页的全部视频跳转链接
    for i in range(1,page+1):
        if i ==1:
            url = f'https://search.bilibili.com/all?keyword={keyword}&from_source=webtop_search&search_source=5'
        else:
            url = f'https://search.bilibili.com/all?keyword={keyword}&from_source=webtop_search&search_source=5&page={i-1}&o={(i-1)*30}'
        # print(url)
        get_jump_url(url,jump_url_list)
        # 翻页休息一秒
        time.sleep(1)
    download_video(jump_url_list,keyword)


if __name__ == '__main__':
    main()

下载中:

文件夹下全是视频:

五、总结

代理IP对于爬虫是密不可分的,但使用代理IP需要遵守相关法律法规和目标网站的使用规则,不得进行非法活动或滥用代理IP服务,高质量代理IP可以帮助爬虫正常采集公开数据信息,有需要代理IP的小伙伴可以试试:代理IP免费试用

如有问题,可以关注公众号 “Bright Data亮数据”,发送问题后会有官方客服进行回复:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java中File文件和IO流

File文件和IO流 概述 FIle是java.io.下面的包&#xff0c;用于代表当前操作系统的文件 可以获文件信息&#xff0c;判断文件类型&#xff0c;创建删除文件夹 注意&#xff1a;File只能对文件本身进行操作&#xff0c;不能读写文件里面存储的数据 …

Docker三分钟部署ElasticSearch平替MeiliSearch轻量级搜索引擎

&#x1f469;&#x1f3fd;‍&#x1f4bb;个人主页&#xff1a;阿木木AEcru (更多精彩内容可进入主页观看) &#x1f525; 系列专栏&#xff1a;《Docker容器化部署系列》 《Java每日面筋》 &#x1f4b9;每一次技术突破&#xff0c;都是对自我能力的挑战和超越。 目录 一、 …

基于web的摩托车销售系统的设计与实现-计算机毕业设计源码031706

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对摩托车销售系统等问题&#xff0c;对摩托车…

手把手教你使用kimi创建流程图【实践篇】

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 引言 在昨日的文章中&#xff0c;我们介绍了如何使用Kimi生成论文中的流程图。今天&#xff0c;我们将更进一步&#xff0c;通过实践案例来展示Kimi在生成流程图方面的应用。这不仅将加…

火绒被骂惨,良心居然也翻车?剩下3款软件还被误认为外国人开发

万万没想到&#xff0c;公认的国产良心软件“火绒”&#xff0c;居然也翻车&#xff0c;很多网友对其大失所望&#xff0c;甚至忍不住吐槽让他不要砸了自己的招牌。 事情的起因是这样的&#xff0c;火绒推出应用商店&#xff0c;并于正式公测&#xff0c;这是要逐渐走向全家桶的…

淘宝店铺商家订单API-接入ERP,多平台订单同步的利器

淘宝开放平台给商家们提供了丰富的API&#xff0c;以方便大家扩展业务流程。但是需要调用这些API&#xff0c;商家们要提交资质审核&#xff0c;审核条件也是很严格的。第三方数据公司的存在可以为大家解决这个问题。 custom-自定义API操作 请求参数 请求参数&#xff1a;ap…

联发科MT6775(Helio P70)_MTK6775处理器规格参数_处理器资料

联发科MT6775(Helio P70)采用了台积电12nm工艺制程八核处理器&#xff0c;由4颗 Arm Cortex-A73 2.1GHz 4颗Arm Cortex-A53 2.0GHz组成。其GPU为ARM Mali-G72 MP3&#xff0c;运行时高达900MHz&#xff0c;比上一代Helio P60效能提升了13%。 值得注意的是&#xff0c;联发科MT…

java打印金字塔paremid和空心金字塔

java打印金字塔 首先确定每行打印几个空格&#xff0c;在确定每行打印几个* 设总层数为layers&#xff0c;当前层数为i。 则每行打印空格数layers-i&#xff0c;每行打印星号数2*i-1 import java.util.Scanner;public class Paremid{public static void main(String[] args) …

搜索引擎的“道”

目录 1. 网页下载&#xff08;解决有没有的问题&#xff09; 1.1 遍历算法 1.1.1 广度优先搜索 1.1.2 深度优先搜索 1.2 网络爬虫 1.2.1 用BFS 还是DFS? 1.2.2 URL提取 1.2.3 哈希表存储URL下载记录 2. 索引构建&#xff08;解决快不快的问题&#xff09; 2.1 布尔…

AI作画Prompt不会写?Amazon Bedrock Claude3.5来帮忙

最新上线的Claude3.5 Sonnet按照官方介绍的数据来看&#xff0c;在多方面超越了CPT-4o&#xff0c;是迄今为止最智能的模型。 而跟上一个版本相比&#xff0c;速度是Claude 3 Opus的两倍&#xff0c;成本只有其五分之一。 Claude3.5 Sonnet不仅擅长解释图表、图形或者从不完…

AI赋能影视解说:Rap说唱玩法拆解!

在影视解说的领域&#xff0c;竞争一直非常激烈&#xff0c;众多创作者纷纷涌入这个热门的赛道。为了在众多声音中脱颖而出&#xff0c;创新成为了关键。最近&#xff0c;一种结合AI技术的解说方式——Rap说唱解说&#xff0c;以其新颖的形式和高效的创作过程&#xff0c;赢得了…

Linux学习第52天:Linux网络驱动实验(三):一往(网)情深

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 许久没有更新&#xff0c;的确是最近有点懈怠了。没有任何借口&#xff0c;接受所有的批评。接下来无论如何也要坚持下去&#xff0c;不管处于什么境地、什么原因&am…

vue3 Cesium 离线地图

1、vite-plugin-cesium 是一个专门为 Vite 构建工具定制的插件&#xff0c;用于在 Vite 项目中轻松使用 Cesium 库。它简化了在 Vite 项目中集成 Cesium 的过程。 npm i cesium vite-plugin-cesium vite -D 2、配置vite.config.js import cesium from vite-plugin-cesiumexp…

生产环境:CentOS 7 Docker 20.10.19离线部署(为离线部署k8s做准备)

背景描述&#xff1a;离线部署Docker环境 在现代IT基础设施中&#xff0c;Docker已经成为应用容器化的标准工具。它简化了应用程序的部署和管理&#xff0c;使开发者和运维工程师能够以更高的效率和一致性进行工作。然而&#xff0c;在某些场景下&#xff0c;由于安全性、网络…

WMS在发展过程中会遇到哪些挑战?

在仓库管理系统&#xff08;Warehouse Management System, WMS&#xff09;的发展过程中&#xff0c;会遇到以下一些挑战&#xff1a; 1、技术整合&#xff1a; 将WMS与现有的ERP&#xff08;企业资源计划&#xff09;、TMS&#xff08;运输管理系统&#xff09;等系统进行有效…

uniapp 小程序 堆叠轮播图 左滑 右滑 自动翻页 点击停止自动翻页

uniapp 小程序 堆叠轮播图 左滑 右滑 自动翻页 点击停止自动翻页 超过指定时间未点击滑动 则继续开始滚动 直接上代码 componentSwiper.vue 需要注意页面切换时清除计时器 <template><view><view class"swiperPanel" touchstart"startMove"…

1.Orange Zero2介绍及刷机启动

Orangepi Zero2 1.Orangepi Zero2简介2.刷机和系统启动 1.Orangepi Zero2简介 为什么学 学习目标依然是Linux系统&#xff0c;平台是ARM架构蜂巢快递柜&#xff0c;配送机器人&#xff0c;这些应用场景用C51,STM32单片机无法实现第三方介入库的局限性&#xff0c;比如刷脸支付…

C++ 教程 - 06 类的封装、继承、多态

文章目录 封装继承多态 封装 在private/protected 模块放置数据或者底层算法实现&#xff1b;在public块提供对外接口&#xff0c;实现相应的功能调用&#xff1b;类的封装案例 #include <iostream> using namespace std;// 类的定义 一般放在头文件 class Stu {public…

STM32中五个时钟源:HSI、HSE、LSI、LSE、PLL

时钟系统是处理器的核心&#xff0c;或者说时钟是单片机的心脏。 1.单片机内部需要储存器、累加器&#xff0c;这些都需要逻辑门电路。比如锁存器就是一个D触发器&#xff0c;而触发器的置1、清0、置数的功能都需要跳变沿。D触发器就是上升沿后存入数据&#xff0c;而这个上升…

Linux 安装ElasticSearch + FSCrawler 扫描本地的文件资源

文章目录 0. 前言1. 安装ElasticSearch1.1 下载安装包1.2 新增用户1.3 解压安装包1.4 更改文件夹用户1.5 修改配置文件1.6 修改系统配置1.7 启动集群 2. 安装FSCrawler2.1 下载安装包2.2 创建配置文件2.3 修改配置文件2.4 启动2.5 验证是否被索引 0. 前言 Elasticsearch 是一个…