首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 解析優酷視頻真實播放地址完整實戰教程

     編輯:Java 程式設計入門

前言

在開發視頻相關應用時,經常需要獲取視頻網站的真實播放地址。本文將詳細講解如何使用 Java 解析優酷視頻的真實下載鏈接,涵蓋從網頁 URL 提取視頻 ID、調用優酷播放列表接口、解密文件 ID 以及拼接最終播放地址的完整流程。

核心思路解析

優酷視頻地址獲取主要分為以下幾個關鍵步驟:

  1. 提取視頻 ID:從優酷視頻頁面 URL 中通過正則表達式提取唯一標識符
  2. 請求播放列表接口:調用 https://v.youku.com/player/getPlayList/VideoIDS/{id} 獲取 JSON 數據
  3. 解析流信息:從返回數據中提取種子、流文件 ID、分段信息等關鍵參數
  4. 解密真實文件 ID:使用種子值通過特定算法還原被打亂的文件 ID
  5. 生成播放地址:結合 SID、分段索引、密鑰 K 值拼接最終的 FLV/MP4 下載鏈接

完整代碼實現

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;

public class VideoTools {
    public static void main(String[] args) throws Exception {
        VideoTools manager = new VideoTools();
        String jsonUrl = manager.getVideoUrl("https://v.youku.com/v_show/id_XMTgzNDA5OTMy.html");
        System.out.println("視頻分段數量: " + jsonUrl.split("#").length);
    }

    public String getVideoUrl(String htmlUrl) throws JSONException {
        // 1. 正則提取視頻 ID
        Pattern p = Pattern.compile(".*id_(\\w+)\\.html");
        Matcher m = p.matcher(htmlUrl);
        String id = "";
        if (m.find()) {
            id = m.group(1);
        }
        System.out.println("提取到的視頻 ID: " + id);

        // 2. 獲取播放列表 JSON
        String jsonContent = getContent("https://v.youku.com/player/getPlayList/VideoIDS/" + id);
        JSONObject jsobj = JSONObject.fromObject(jsonContent);
        JSONArray dataArr = jsobj.getJSONArray("data");
        JSONObject videoInfo = dataArr.getJSONObject(0);

        // 3. 解析核心參數
        String title = videoInfo.getString("title");
        double seed = videoInfo.getDouble("seed");
        JSONObject streamFileIds = videoInfo.getJSONObject("streamfileids");
        
        String format = "mp4";
        String fileId = null;
        try {
            fileId = streamFileIds.getString("mp4");
        } catch (JSONException e) {
            System.out.println("無 MP4 格式,嘗試 FLV");
            try {
                fileId = streamFileIds.getString("flv");
                format = "flv";
            } catch (JSONException e1) {
                System.out.println("無可用格式");
                return "";
            }
        }

        // 4. 解密真實文件 ID
        String realFileId = getFileID(fileId, seed);
        String idLeft = realFileId.substring(0, 8);
        String idRight = realFileId.substring(10);

        // 5. 生成 SID 並拼接分段地址
        String sid = genSid();
        JSONObject segs = videoInfo.getJSONObject("segs");
        JSONArray formatArr = segs.getJSONArray(format);
        StringBuilder videoUrls = new StringBuilder();

        for (int i = 0; i < formatArr.size(); i++) {
            JSONObject seg = formatArr.getJSONObject(i);
            String k = seg.getString("k");
            String segmentIndex = String.format("%02X", i);
            String url = "https://f.youku.com/player/getFlvPath/sid/" + sid + "_" + segmentIndex 
                       + "/st/" + format + "/fileid/" + idLeft + segmentIndex + idRight + "?K=" + k;
            System.out.println("分段 " + i + ": " + url);
            videoUrls.append(url).append("#");
        }
        return videoUrls.toString();
    }

    // 文件 ID 解密算法
    private static String getFileID(String fileid, double seed) {
        String mixed = getFileIDMixString(seed);
        String[] ids = fileid.split("\\*");
        StringBuilder realId = new StringBuilder();
        for (String idStr : ids) {
            int idx = Integer.parseInt(idStr);
            realId.append(mixed.charAt(idx));
        }
        return realId.toString();
    }

    // 生成會話 ID
    public static String genSid() {
        int i1 = (int) (1000 + Math.floor(Math.random() * 999));
        int i2 = (int) (1000 + Math.floor(Math.random() * 9000));
        return System.currentTimeMillis() + "" + i1 + "" + i2;
    }

    // 混淆字符串生成(核心解密邏輯)
    private static String getFileIDMixString(double seed) {
        StringBuilder mixed = new StringBuilder();
        StringBuilder source = new StringBuilder("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/\\:._-1234567890");
        int len = source.length();
        for (int i = 0; i < len; ++i) {
            seed = (seed * 211 + 30031) % 65536;
            int index = (int) Math.floor(seed / 65536 * source.length());
            mixed.append(source.charAt(index));
            source.deleteCharAt(index);
        }
        return mixed.toString();
    }

    // HTTP 請求工具方法
    public static String getContent(String strUrl) {
        try {
            URL url = new URL(strUrl);
            BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
            StringBuffer sb = new StringBuffer();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            br.close();
            return sb.toString();
        } catch (Exception e) {
            return "error open url:" + strUrl;
        }
    }
}

關鍵技術點深度解析

1. 文件 ID 解密機制

優酷將真實文件 ID 通過種子值進行了置換加密。getFileIDMixString 方法利用線性同餘生成器(LCG)根據種子生成一個打亂後的字符映射表,然後 getFileID 將加密 ID 中的每個數字索引映射回原始字符,從而還原真實文件 ID。

2. 分段下載架構

優酷視頻採用分段存儲,每個分段擁有獨立的密鑰 K。最終播放地址包含:SID(會話標識)、分段索引(十六進制)、流類型、解密後的文件 ID 片段以及密鑰 K。

3. 格式降級策略

代碼實現了 MP4 優先、FLV 降級的策略,通過異常捕獲優雅處理不同視頻的可用格式差異。

注意事項與避坑指南

  • 接口時效性:優酷播放接口可能隨時變更,生產環境建議增加緩存與降級機制
  • 反爬蟲機制:高頻請求會觸發 IP 封禁,需控制請求頻率並模擬真實 User-Agent
  • 版權合規:僅供技術學習研究,商業使用需獲得優酷官方授權
  • 依賴庫:示例使用 net.sf.json(json-lib),現代項目建議遷移至 Jackson 或 Gson

擴展應用場景

掌握此解析技術後,可應用於:視頻下載工具開發、視頻內容聚合平台、自動化測試驗證視頻鏈接有效性、視頻轉碼預處理流程等場景。同樣原理可擴展至騰訊視頻、愛奇藝等其他平台,只需分析各自的接口協議與加密算法。

總結

本文提供了完整的優酷視頻地址解析 Java 實現,從 URL 解析到最終播放鏈接生成,涵蓋了網絡請求、JSON 解析、加密算法逆向、字符串操作等核心技術。理解這套流程不僅能解決具體業務需求,更能鍛鍊逆向分析與網絡協議解析能力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved