码峰博客 – 码而思

分享积累从此时此刻开始

篡改猴下载 MP4

有道精品课

打开视频页面。视频业的链接以 https://live.youdao.com/ 开头

1.安装 篡改猴篡改猴下载看这里

2.添加新脚本

3. 输入如下内容

// ==UserScript==
// @name         有道精品课 - MP4下载
// @namespace    http://tampermonkey.net/
// @version      2025-09-14
// @description  try to take over the world!
// @author       You
// @match        https://live.youdao.com/*
// @grant        none
// @icon         https://www.google.com/s2/favicons?sz=64&domain=deepseek.com
// ==/UserScript==


(function() {
    'use strict';




        // 交互界面 =======================================================================
        function createStyles() {
            const style = document.createElement('style');
            style.textContent = `

                .container {
                    background: red;
                    padding: 20px;
                    border-radius: 8px;
                    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
                    width: 100%;
                    max-width: 200px;
                    position: fixed;
                    top: 0px;
                    right: 0px;
                }

                .input-group {
                    margin-bottom: 15px;
                }

                label {
                    display: block;
                    margin-bottom: 5px;
                    font-weight: bold;
                }

                input {
                    width: 100%;
                    padding: 8px;
                    border: 1px solid #ddd;
                    border-radius: 4px;
                }


                .user-input {
                    color: #28a745;
                    font-weight: bold;
                }

                button {
                    background-color: #4CAF50;
                    color: white;
                    border: none;
                    padding: 10px 15px;
                    border-radius: 4px;
                    cursor: pointer;
                    width: 100%;
                    font-size: 16px;
                }

                button:hover {
                    background-color: #45a049;
                }
            `;
            document.head.appendChild(style);
        }

        // 创建页面结构
        function createPage() {
            // 创建容器
            const container = document.createElement('div');
            container.className = 'container';


            // 创建输入组 - 提示信息
            const messageGroup = document.createElement('div');
            messageGroup.className = 'input-group';

            const messageLabel = document.createElement('label');
            messageLabel.textContent = '课程序号:';
            messageLabel.htmlFor = 'promptMessage';

            const messageInput = document.createElement('input');
            messageInput.type = 'text';
            messageInput.id = 'promptMessage';
            messageInput.placeholder = '输入课程序号,建议使用2位';

            // 创建按钮
            const button = document.createElement('button');
            button.id = 'demoBtn';
            button.textContent = '下载';

            messageGroup.appendChild(messageLabel);
            messageGroup.appendChild(messageInput);



            container.appendChild(messageGroup);
            container.appendChild(button);

            document.body.appendChild(container);


            // 添加事件监听
            button.addEventListener('click', function() {
                window.localStorage.setItem('promptMessage', messageInput.value);

                saveMP4()
            });
        }



        function setIntpuValue(value){
            const messageInput = document.getElementById('promptMessage');
            messageInput.value = value;
        }

        function init() {
            // 创建样式
            createStyles();

            // 创建页面元素
            const elements = createPage();


            // 默认值
            let promptMessageValue = window.localStorage.getItem('promptMessage');
            if(!promptMessageValue){
                promptMessageValue = '01';
            }else{
                let v = parseInt(promptMessageValue)+1;
                // 不足2位,补0
                if(v<10){
                    promptMessageValue = '0'+v;
                }else{
                    promptMessageValue = v;
                }
            }
            setIntpuValue(promptMessageValue);
        }

        //document.addEventListener('DOMContentLoaded', init);
        init()





    // 下载处理 =======================================================================



    const saveMP4 = function(context){
        // mp4 地址
        const mp4url = document.getElementById('myVideo_html5_api').src;

        // 文件名 序号+标题+文件后缀
        const fileName = document.getElementById('promptMessage').value +"."+ document.title + '.txt';

        try {

            const blob = new Blob([mp4url], { type: 'application/octet-stream' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = fileName;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
            console.log('二进制内容已保存:', fileName);
        } catch (e) {
            console.error('处理二进制响应时出错:', e);
        }
  
    }


})();

4. 点击右侧的下载按钮,就会提示保存 .txt 文件,文件中是 mp4 的视频链接。将同一课程的所有视频都保存后,使用 python 批量下载。

5.使用python 代码批量下载

# pip install requests tqdm

import requests
import os
import warnings
from tqdm import tqdm  # 用于显示进度条

# 抑制urllib3的SSL警告
warnings.filterwarnings('ignore', message='Unverified HTTPS request')

def download_mp4_with_headers(url, output_path, headers=None, verify_ssl=True):
    """
    从URL下载MP4文件,支持自定义请求头
    
    Args:
        url (str): MP4文件的URL地址
        output_path (str): 保存文件的本地路径
        headers (dict): 自定义请求头,默认为None
        verify_ssl (bool): 是否验证SSL证书,默认为True
    """
    # 默认请求头,模拟浏览器行为
    default_headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
        'Accept': '*/*',
        'Accept-Language': 'en-US,en;q=0.5',
        'Connection': 'keep-alive',
    }
    
    # 合并默认请求头和自定义请求头
    if headers:
        final_headers = {**default_headers, **headers}
    else:
        final_headers = default_headers
    
    try:
        # 发送GET请求,stream=True表示流式下载
        response = requests.get(
            url, 
            headers=final_headers, 
            stream=True, 
            verify=verify_ssl,
            timeout=30
        )
        response.raise_for_status()  # 检查请求是否成功
        
        # 获取文件总大小(如果服务器提供了Content-Length头)
        total_size = int(response.headers.get('content-length', 0))
        block_size = 8192  # 每次下载的块大小
        
        # 创建输出目录(如果不存在)
        dir_name = os.path.dirname(output_path)
        if dir_name:
            os.makedirs(dir_name, exist_ok=True)
        
        # 使用进度条显示下载进度
        with open(output_path, 'wb') as file, tqdm(
            desc=output_path,
            total=total_size,
            unit='iB',
            unit_scale=True,
            unit_divisor=1024,
        ) as bar:
            for chunk in response.iter_content(chunk_size=block_size):
                if chunk:
                    size = file.write(chunk)
                    bar.update(size)
        
        print(f"\n文件已成功保存到: {output_path}")
        return True
    
    except requests.exceptions.RequestException as e:
        print(f"下载过程中出现错误: {e}")
        return False
    except Exception as e:
        print(f"发生未知错误: {e}")
        return False


# 单个文件下载
def download_single_file(url, output_path):
    """
    从URL下载单个文件,支持自定义请求头
    
    Args:
        url (str): 文件的URL地址
        output_path (str): 保存文件的本地路径
        headers (dict): 自定义请求头,默认为None
        verify_ssl (bool): 是否验证SSL证书,默认为True
    """

    # 使用示例
    video_url = url 
    output_file = output_path
    
    # 自定义请求头(可选)
    custom_headers = {
        'Host':'stream.ydstatic.com',
        'Range':'bytes=0-',
        'Referer': "https://live.youdao.com/",
        'User-agent':'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1',
    }
    
    # 下载文件
    success = download_mp4_with_headers(
        url=video_url,
        output_path=output_file,
        headers=custom_headers,
        verify_ssl=False  # 如果是自签名证书,可以设置为False
    )
    
    if success:
        print("下载成功!")
    else:
        print("下载失败!")

if __name__ == "__main__":
    # 使用示例
        # 单个文件下载
    # main(r'E:\111\【有道博闻美育】高端文学·秋实班\04.茅盾文学奖之《东藏记》一.m3u8')

    # 批量下载
    directory = r'E:\111\7.《实景课》'

    # 遍历目录下的所有文件
    for filename in os.listdir(directory):
        # 检查文件是否为m3u8文件
        if filename.endswith('.txt'):
            # 构建完整的文件路径
            txt_file_path = os.path.join(directory, filename)

            # 读取文件内容
            mp4_url = ""
            with open(txt_file_path, 'r', encoding='utf-8') as file:
                mp4_url = file.read()
            print(f"当前文件: {mp4_url} ")

            save_path = os.path.join(directory, filename.replace('.txt', '.mp4'))
            print(f"保存路径: {save_path} ")
            # 下载
            download_single_file(mp4_url, save_path)