Python爬虫实战案例——第二例

某某美剧剧集下载(从搜索片名开始)
本篇文章主要是为大家提供某些电影网站的较常规的下载电影的分析思路与代码思路(通过爬虫下载电影),我们会从搜索某部影片的关键字开始直到成功下载某一部电影。

地址:aHR0cHM6Ly93d3cuOTltZWlqdXR0LmNvbS9pbmRleC5odG1s

先来分析页面

在这里插入图片描述

打开开发者工具,然后再搜索框输入任意内容开始搜索影片(如搜索战火)并抓包

在这里插入图片描述

从XHR来看的话返回的都是js文件,所以我们可以先考虑document中的html文档是否包含了我们需要的有效数据。

在这里插入图片描述

document中只返回了一个包,并且通过预览来看的话我们可以看到通过关键字搜索出来的电影是存在于这个html中的,所以我们就可以直接通过xpath解析将这些电影的片名解析出来,便于后面我们对影片进行选择。然后就可以进入到电影的详情页面(xpath解析出详情页的url)了。例如此处我们选择《兄弟连》这部电影。

在这里插入图片描述

进入到详情页之后,我们需要判断这部影片是否已经更新完成,因为下面我们需要选择播放线路,不同的播放线路已更新的剧集可能不同,但是经过对多部影片的详情页分析(此处不再贴图,大家自己去观察)发现,已完结的影片是不会存在上述问题的。但是正在连载中的影片可能就存在这样的问题,所以我们需要判断一下已经连载的剧集与这些播放线路中的剧集集数是否相等,如果相等的话才是可用的线路,否则是不可用的线路。当然也有可能存在一条线路都无法播放的情况,这个就是服务器的问题了,咱们客户端这边是没办法处理的。之后我们就要根据选择的线路去到播放页面就可以准备下载电视剧了。

此处我们选择的是九九云线路,来到播放页面之后通过抓包我们会发现并没有媒体文件,但是存在着m3u8与ts的包,因此我们能够判断出这个站点的视频是被分割成很多分的片段了。

在这里插入图片描述

接下来就是要想办法把这些ts视频下载下来了,通常情况下,这些文件的url会存在于一个m3u8的文件之中,所以我们需要先将m3u8下载下来。从播放页面的源码中我们可以解析出m3u8文件的下载地址(为了方便此处我就不再去请求源码了,直接从elements中看,大家平时的时候一定是养成习惯把源码下载到本地进行分析)

在这里插入图片描述

然后将next后面的url解析出来再进行请求,就会看到里面存在着一个新的m3u8文件的地址。

在这里插入图片描述

接下来就是通过正则将这个文件中存在的这个地址提取出来进行拼接再进行请求就能够获取到所有的ts文件所在的地址了。

在这里插入图片描述

下一步就是将这些ts文件的地址提取出来,同样我们选择正则进行提取(或者使用专门处理m3u8的第三方包进行提取),提取出来后拼接成正常的链接,存放到一个列表中,然后再遍历列表依次请求这些url并按照顺序将视频进行保存。

在这里插入图片描述

保存之后通过ffmpeg对视频进行合成,关于ffmpeg的配置请大家自行查阅一下相关资料。

在这里插入图片描述

合成后的视频

在这里插入图片描述

由于时间关系,只下载了200个片段进行合成,有兴趣的朋友可以改写成并发请求的方式下载所有的片段进行合成。完整代码如下:

import os.path
import re
import requests
import urllib3
from lxml import etree



class SendRequest:
    """基本请求模板,待完善"""
    urllib3.disable_warnings()
    def __init__(self):
        self.ABS_PATH = os.path.abspath(os.path.dirname(__file__))
        self.url = ''
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36'
        }
        self.cookies = {}  # cookie设置
        self.data = {}  # 表单数据
        self.page = 1  # 翻页控制参数
        self.session = requests.session()
        # self.movie = '测试'
        # print(f'{self.ABS_PATH}/{self.movie}(临时文件)/{self.movie}.m3u8')
        # print(f'{self.ABS_PATH}/{self.movie}/{self.movie}.mp4')

    @property
    def UGetRequest(self):
        response = self.session.get(url=self.url, headers=self.headers, cookies=self.cookies, verify=False)
        return response

    @UGetRequest.setter
    def UGetRequest(self, kwargs: dict):
        if kwargs.get('url'):
            self.url = kwargs.get('url')
        if kwargs.get('referer'):
            self.headers['referer'] = kwargs.get('referer')

    @property
    def UPostRequest(self):
        response = self.session.post(url=self.url, headers=self.headers, cookies=self.cookies, data=self.data,
                                     verify=False)
        return response

    @UPostRequest.setter
    def UPostRequest(self, kwargs: dict):
        if kwargs.get('url'):
            self.url = kwargs.get('url')
        if kwargs.get('referer'):
            self.headers['referer'] = kwargs.get('referer')


class MeiJu99(SendRequest):
    def __init__(self):
        super().__init__()

    def synthesis(self):
        """合成视频"""
        if not os.path.exists(self.movie):
            os.mkdir(self.movie)
        cmd = f'ffmpeg.exe -f concat -safe 0 -i {self.ABS_PATH}\\{self.movie}(临时文件)\\{self.movie}.m3u8 -c copy {self.ABS_PATH}\\{self.movie}\\{self.movie}.mp4'
        os.system(cmd)

    def download_mvs(self, total_mv_urls):
        """下载所有片段"""
        if not os.path.exists(self.movie+'(临时文件)'):
            os.mkdir(self.movie+'(临时文件)')
        num = 1
        # 按照ffmpeg的格式将ts文件的路径写入到一个m3u8文件之中用于合成视频
        new_m3u8_file = open(self.movie+'(临时文件)'+'/'+self.movie+'.m3u8', 'a', encoding='utf-8')
        for url in total_mv_urls:
            self.UGetRequest = {'url': url}
            res = self.UGetRequest
            with open(self.movie+'(临时文件)'+'/'+str(num)+'.ts', 'wb')as f:
                f.write(res.content)
                new_m3u8_file.write("file '%s\%s\%d.ts'" % (self.ABS_PATH, self.movie+'(临时文件)', num))
                new_m3u8_file.write('\n')
                print(str(num) + '下载成功')
                num+=1
            if num == 201:
                break
        new_m3u8_file.close()
        self.synthesis()

    def play_page(self, play_pages_url):
        """播放页面提取下载链接"""
        self.UGetRequest = {'url': play_pages_url}
        response = self.UGetRequest
        text_html = response.content.decode()
        with open('playpage.html', 'w', encoding='utf-8')as f:
            f.write(text_html)
        m3u8_url = re.findall('var next="(.*?)";var prePage=', text_html)[0]    # 提取播放页面中的m3u8文件的地址
        self.UGetRequest = {'url': m3u8_url}
        m3u8_file = self.UGetRequest.content
        with open('1.m3u8', 'wb')as f:
            f.write(m3u8_file)
        # 请求上方获取到的m3u8_url以获取存放了ts地址的m3u8
        last_m3u8_url = m3u8_url.split('/2')[0] + re.search('/\d+/\w+/[\d+kb/]*\w+/index\.m3u8', m3u8_file.decode()).group()
        self.UGetRequest = {'url': last_m3u8_url}
        response = self.UGetRequest.content.decode()
        # 解析并保存所有的ts地址
        total_mv_urls = [m3u8_url.split('/2')[0]+i for i in re.findall('/\d+/\w+/\d+\w+/hls/\w+\.ts', response)]
        self.download_mvs(total_mv_urls)

    def index(self, index_url):
        """电影详情页面"""
        self.UGetRequest = {'url': index_url}
        response = self.UGetRequest
        text_html = response.content.decode()
        with open('index.html', 'w', encoding='utf-8')as f:
            f.write(text_html)
        tree = etree.HTML(text_html)
        using_lines = tree.xpath('//*[@id="playTab"]/div[1]/ul//li//text()')    # 可使用线路(名称)
        play_tab = tree.xpath('//*[@id="playTab"]/div')     # 下载线路
        mv_information = ''.join(tree.xpath('//*[@id="zanpian-score"]/ul//text()'))     # 电影信息
        status = ''.join(tree.xpath('//*[@id="zanpian-score"]/ul/li[2]//text()'))
        if '完结' not in status:
            numbers_sets = ''.join(re.findall('集数:共(.*?)集 每集\d+分钟|状态:更新至(.*?)集', mv_information)[0])
            for i, tab in zip(range(len(using_lines)), play_tab[1:]):
                tab_num = len(tab.xpath('./ul/li'))
                if tab_num == int(numbers_sets):
                    print('%d.' % (i+1), using_lines[i]+'(可用)', end='\t')
                else:
                    print('%d.' % (i+1), using_lines[i]+'(不可用)', end='\t')
        else:
            for i, tab in zip(range(len(using_lines)), play_tab[1:]):
                print('%d.' % (i + 1), using_lines[i], end='\t')
        print()
        download_num = int(input('请选择下载线路(输入编号):'))
        play_pages_urls = ['https://www.99meijutt.com'+i for i in play_tab[download_num].xpath('./ul//li/a/@href')]
        for play_pages_url in play_pages_urls:
            self.play_page(play_pages_url)
            break

    def search(self):
        """搜索页面采集"""
        titles = []
        self.UPostRequest = {'url': 'https://www.99meijutt.com/search.php'}
        self.data['searchword'] = input('请输入影片关键字或主演名:')
        response = self.UPostRequest
        text_html = response.content.decode()
        with open('search.html', 'w', encoding='utf-8') as f:
            f.write(text_html)
        tree = etree.HTML(text_html)
        div_lst = tree.xpath('//*[@id="content"]/div')
        print('搜索到的电影如下:')
        for i, div in zip(range(1, len(div_lst)), div_lst):  # 遍历数组与div列表为标题设置编号
            title = div.xpath('./div[1]/a/@title')[0]
            if i % 2 != 0 and i != len(div_lst)-1:
                print(str(i) + '.' + title, end='\t\t')
            else:
                print(str(i) + '.' + title)
            titles.append(title)
        num = int(input('请输入您要下载的电影序号:'))
        self.movie = titles[num-1]
        index_url = 'https://www.99meijutt.com' + div_lst[num-1].xpath('./div[1]/a/@href')[0]
        self.index(index_url)


if __name__ == '__main__':
    mj = MeiJu99()
    mj.search()

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

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

相关文章

基于全新电脑环境安装pytorch的GPU版本

前言: 距离第一次安装深度学习的GPU环境已经过去了4年多(当时TensorFlow特别麻烦),现在发现安装pytorch的GPU版本还是很简单方便的,流程记录如下。 安装步骤: 步骤一:官网下载Anaconda Free…

局域网中电脑共享文件给手机

学习资源: 局域网共享:这样设置,你可以轻松拷贝任何电脑的文件。_哔哩哔哩_bilibili 可以实现什么效果? 连接同一个WIFI,电脑端为服务端,提供共享文件,手机是客户端,可以读取服务端…

C语言——指针进阶(一)

目录 ​编辑 一.字符指针 1.1 基本概念 1.2 面试题 二.指针数组 三.数组指针 3.1 数组指针的定义 3.2 &数组名VS数组名 3.3 数组指针的使用 四.数组参数、指针参数 4.1 一维数组传参 ​编辑 4.2 二维数组传参 4.3 一级指针传参 4.4 二级指针传参 ​编辑 五.…

windows系统 Fooocus 图片生成模型 ,4-6GB显存即可玩,27S/p

安装步骤: 1.下载程序代码框架,大小2GB ,下载 ​​​​​​https://github.com/lllyasviel/Fooocus/releases/download/1.0.35/Fooocus_win64_1-1-1035.7z 2.下载模型文件sd_xl_base_1.0_0.9vae.safetensors ,大小6GBhttps://huggingface.co/stabilityai/stable-diffusion-x…

软件配置安装(破解)--- maven下载配置

检查环境是否已有 首先检查一下电脑里有无maven环境,有的话就不用安装了 查看path环境中没有maven,开始准备接下来的重头戏 下载maven 下载bin.zip版 解压mavenxxxbin.zip (建议把解压的文件放在一个文件夹内,命名英文的env…

利用敏捷开发工具实现敏捷项目管理的实践经验分享

Scrum中非常强调公开、透明、直接有效的沟通,这也是“可视化的管理工具”在敏捷开发中如此重要的原因之一。通过“可视化的管理工具”让所有人直观的看到需求,故事,任务之间的流转状态,可以使团队成员更加快速适应敏捷开发流程。 …

8.缓冲区管理

第五章 I/O管理 缓冲区管理 双缓冲区&#xff1a;T<CM 假设初始状态缓冲区1满&#xff0c;缓冲区2空&#xff0c;工作区为空。 刚开始缓冲区2为空&#xff0c;所以设备可以向缓冲区2中冲入数据耗时T&#xff0c;另一方面刚开始缓冲区1中是满的&#xff0c;所以刚开始就可…

前端vue3+typescript架构

1、vue creat 项目名称 选择自定义 选择需要的依赖 选择vue3 一路enter&#xff0c;选择eslistprettier 继续enter&#xff0c;等待安装 按步骤操作&#xff0c;项目启动成功 2、vscode安装5款插件 2、代码保存自动格式化&#xff0c;保证每个开发人员代码一致&#xff0c;根目…

LeetCode 周赛上分之旅 #42 当 LeetCode 考树上倍增,出题的趋势在变化吗

⭐️ 本文已收录到 AndroidFamily&#xff0c;技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架&#xff0c;你的思考越抽象&#xff0c;它能覆盖的问题域就越广&#xff0c;理解难度…

DevOps系列文章 之 Python基础

字符串 定义字符串 1.python中字符串被定义为引号之间的字符集合 2.python支持使用成对的单引号或双引号 3.无论单引号&#xff0c;还是双引号&#xff0c;表示的意义相同 4.python还支持三引号&#xff08;三个连续的单引号或者双引号&#xff09;&#xff0c;可以用来包含特…

【Linux】深入理解文件操作

文章目录 初次谈论文件重温C语言文件操作系统文件操作接口openwriteread 再次谈论文件文件描述符文件描述符的分配规则 重定向什么是重定向重定向的本质系统调用接口实现重定向<、>、>> 初次谈论文件 开始之前先谈论一下关于文件的一些共识性问题。 一个文件可以…

http协议与apache

http概念&#xff1a; 互联网&#xff1a;是网络的网络&#xff0c;是所有类型网络的母集 因特网&#xff1a;世界上最大的互联网网络。即因特网概念从属于互联网概念 万维网&#xff1a;万维网并非某种特殊的计算机网络&#xff0c;是一个大规模的、联机式的信息贮藏库&…

SpringCloud Alibaba实战和源码(7)Skywalking

什么是SkyWalking Skywalking是由国内开源爱好者吴晟开源并提交到Apache孵化器的产品&#xff0c;它同时吸收了Zipkin /Pinpoint /CAT 的设计思路。特点是&#xff1a;支持多种插件&#xff0c;UI功能较强&#xff0c;支持非侵入式埋点。目前使用厂商最多&#xff0c;版本更新较…

keepalived+lvs+nginx高并发集群

keepalivedlvsnginx高并发集群 简介&#xff1a; keepalivedlvsnginx高并发集群&#xff0c;是通过LVS将请求流量均匀分发给nginx集群&#xff0c;而当单机nginx出现状态异常或宕机时&#xff0c;keepalived会主动切换并将不健康nginx下线&#xff0c;维持集群稳定高可用 1.L…

【Java】Java基础

环境准备 安装JDK和JRE 下载JDK&#xff0c;可以在官网Java Downloads | Oracle 中国下载&#xff0c;但是这里需要注册才能够下载。在Index of java-local/jdk (huaweicloud.com)也可以下载到&#xff0c;但是版本比较老&#xff0c;关系不大&#xff0c;直接下载&#xff0…

node-red - 读写操作redis

node-red - 读写操作redis 一、前期准备二、node-red安装redis节点三、node-red操作使用redis节点3.1 redis-out节点 - 存储数据到redis3.2 redis-in节点 - 查询redis数据 附录附录1&#xff1a;redis -out节点示例代码附录2&#xff1a;redis -in节点示例代码 一、前期准备 安…

On-Manifold Optimization: Local Parameterization

Overview Manifold Space vs Tangent Space Jacobian w.r.t Error State Jacobian w.r.t Error State vs True State According 1 2.4, The idea is that for a x ∈ N x \in N x∈N the function g ( δ ) : f ( x ⊞ δ ) g(\delta) : f (x \boxplus \delta) g(δ):f(x…

《C和指针》笔记10:作用域

结合上面的例子讲解C语言的作用域。 1. 代码块作用域 (block scope) 位于一对花括号之间的所有语句称为一个代码块。任何在代码块的开始位置声明的标识符都具有代码块作用域 (block scope)&#xff0c;表示它们可以被这个代码块中的所有语句访问。上图中标识为6、7、9、10的变…

视频云存储/安防监控视频智能分析网关V3:占道经营功能详解

违规占道经营者经常会在人流量大、车辆集中的道路两旁摆摊&#xff0c;导致公路交通堵塞&#xff0c;给居民出行的造成不便&#xff0c;而且违规占路密集的地方都是交通事故频频发生的区域。 TSINGSEE青犀视频云存储/安防监控视频/AI智能分析网关V3运用视频AI智能分析技术&…

如何延长周末体验感

美好的周末永远都是从周五开始 为了享受周末的美好时光一定要在周五下班前把工作中应该处理的事情处理好&#xff0c;避免突发事件影响后续的计划。 此外过周五晚上开始做让自己感到开心的事情&#xff0c;以此让自己感觉到周末已经开始了。包括单不限于 享受美食 周五晚上是一…