python网络请求:下载mp4文件并获取时长

python网络请求:下载mp4文件并获取时长

import json
import os
import random
import subprocess
import time

import requests
import urllib3
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

class CourseLearning:
    def __init__(self, cookie, le_id):
        self.website_action_main_url = 'https://*************/front/command/WebSiteAction'
        self.lesson_action_main_url = 'https://*************/front/command/LessonAction'
        self.mp4_main_url = 'https://media*************/resource//mp4Course'
        self.mp4_save_dir = self.get_current_file_dir() + os.sep + 'mp4'
        self.json_headers = {
            'Content-Type': 'application/json;charset=UTF-8',
            'Cookie': cookie
        }
        self.html_headers = {
            'Content-Type': 'text/html;charset=utf-8',
            'Cookie': cookie
        }
        self.mp4_headers = {
            'Content-Type': 'video/mp4'
        }
        self.le_id = le_id
        self.course_list = None

    @staticmethod
    def get_current_file_dir():
        return os.path.abspath(os.path.dirname(__file__))

    @staticmethod
    def dict2str(dct):
        items = [f'{key}={value}' for key, value in dct.items()]
        return '&'.join(items)

    @staticmethod
    def get_sid():
        return random.random()

    def study_mp4(self, info):
        data = {
            'flag': 'studyMp4',
            'le_id': self.le_id,
            'preview': 1,
            'mp4Id': info['id'],
            'duration': 0,
            'sid': self.get_sid()
        }
        url = self.lesson_action_main_url + '?' + self.dict2str(data)
        res = requests.get(url, headers=self.html_headers)
        if res.status_code != 200:
            print('study_mp4请求异常')
        else:
            print('study_mp4请求正常')


    def go_to_student(self):
        data = {
            'flag': 'gotoStudent20140504'
        }
        url = self.website_action_main_url + '?' + self.dict2str(data)
        res = requests.post(url, headers=self.json_headers)
        if res.status_code != 200:
            print('go_to_student请求异常')
        else:
            print('go_to_student请求正常')


    def get_lesson_chapter(self):
        data = {
            'flag': 'getLessonChapter',
            'le_id': self.le_id,
            'sid': self.get_sid()
        }
        url = self.lesson_action_main_url + '?' + self.dict2str(data)
        res = requests.post(url, headers=self.json_headers)
        if res.status_code != 200:
            print('请求课程列表异常')
        else:
            data_dict = json.loads(res.text)
            course_data = data_dict['data']
            details = [each['details'] for each in course_data]
            # 压平 过滤已学部分
            self.course_list = [i for sublist in details for i in sublist if i['schedule'] < 100]


    @staticmethod
    def download_mp4(url, save_path):
        try:
            # 创建会话并设置重试机制
            session = requests.Session()
            retries = Retry(total=5, backoff_factor=1, status_forcelist=[502, 503, 504])
            session.mount('https://', HTTPAdapter(max_retries=retries))

            res = session.get(url, stream=True, timeout=30)
            res.raise_for_status()  # 确保请求成功

            # 获取文件总大小
            # total_size = int(res.headers.get('content-length', 0))
            # print(f'视频总大小: {total_size}字节')

            # 逐块下载并保存到本地文件
            with open(save_path, 'wb') as f:
                for chunk in res.iter_content(chunk_size=8192):
                    if chunk:
                        f.write(chunk)
            print(f'视频下载完成,保存路径: {save_path}')
        except requests.exceptions.RequestException as e:
            print(f'视频下载失败: {e}')


    @staticmethod
    def get_video_duration(video_path):
        try:
            if not os.path.isfile(video_path):
                print(f"视频文件路径错误: {video_path}")
                return None
            # 使用 ffmpeg 获取视频时长
            result = subprocess.run(
                ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of",
                 "default=noprint_wrappers=1:nokey=1", video_path],
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT
            )
            duration = round(float(result.stdout.decode().strip()), 2)
            print(f"视频时长:{duration} 秒")
            return duration
        except Exception as e:
            print(f"获取视频时长失败:{e}")
            return None


    def update_mp4_time(self, info):
        data = {
            'flag': 'updateMp4Time',
            'le_id': self.le_id,
            'mp4Id': info['id'],
            'totalTime': info['totalTime']
        }
        url = self.lesson_action_main_url + '?' + self.dict2str(data)
        res = requests.post(url, headers=self.json_headers)
        if res.status_code != 200:
            print('update_mp4_time请求返回异常')
        else:
            print('update_mp4_time请求成功')


    def update_time(self, info):
        data = {
            'flag': 'updateTime',
            'le_id': self.le_id,
            'mp4Id': info['id']
        }
        url = self.lesson_action_main_url + '?' + self.dict2str(data)
        res = requests.post(url, headers=self.json_headers)
        if res.status_code != 200:
            print('update_time请求返回异常')
        else:
            print('update_time请求成功')

    def update_study_statistics_info(self, index, info, current_time):
        data = {
            'flag': 'updateStudyStatisticsInfo',
            'le_id': self.le_id,
            'mp4Id': info['id'],
            'currentTime': current_time,
            'sid': self.get_sid()
        }
        url = self.lesson_action_main_url + '?' + self.dict2str(data)
        res = requests.post(url, headers=self.json_headers)
        if res.status_code != 200:
            print(f'第{index + 1}次update_study_statistics_info请求返回异常: {current_time}s')
        else:
            print(f'第{index + 1}次update_study_statistics_info请求成功: {current_time}s')
        return res


if __name__ == '__main__':
    my_cookie = '*******************'
    lesson_id = 'cd73ea2304d54b0596fc48c560a6be9d'

    courseLearning = CourseLearning(my_cookie, lesson_id)

    # 1. 获取学习列表
    courseLearning.get_lesson_chapter()

    if not courseLearning.course_list:
        print('学习列表为空或已学完')

    for item in courseLearning.course_list:
        print('=====课程章节[%s], 课程名称[%s]=====' % (item['chapter'], item['le_name']))

        # 2. 请求开始学习
        courseLearning.study_mp4(item)

        # courseLearning.go_to_student()

        mp4_download_url = courseLearning.mp4_main_url + item['enter_url']
        mp4_name = item['enter_url'].split('/')[-1]
        mp4_save_path = courseLearning.mp4_save_dir + os.sep + mp4_name

        # 3.下载视频,并获取视频时长
        courseLearning.download_mp4(mp4_download_url, mp4_save_path)
        item['totalTime'] = courseLearning.get_video_duration(mp4_save_path)
        if item['totalTime'] is None:
            raise TypeError('视频时长为None')

        # 4.更新mp4时长
        courseLearning.update_mp4_time(item)

        # 5.更新时间
        courseLearning.update_time(item)

        # 6.每分钟更新播放信息
        total_index = int(item['totalTime'] / 60) + 1
        for i in range(total_index):
            time.sleep(10)
            seed_second = round(random.random() * 0.5, 2)
            curr_time = ((i + 1) * 60 - seed_second) if i < total_index - 1 else item['totalTime']
            resp = courseLearning.update_study_statistics_info(i, item, curr_time)
            if resp.status_code != 200:
                break

posted @ 2025-04-24 11:30  Steven0325  阅读(64)  评论(0)    收藏  举报