从YouTube获取FLV URL

时间:2014-01-24 17:52:33

标签: c# regex youtube download

有许多非常相似的问题,但到目前为止,我找不到任何可以直接回答这个问题的问题。很多回复包括“查看这个的源代码”并包含一个链接,不幸的是我正在努力分析这些链接中的源代码,所以我希望有人可以一步一步地给我一些东西。

这是我到目前为止所做的:

  1. 最终用户的请求链接(例如www.youtube.com/watch?v=2FlgVN03fNM)
  2. 将HTTP请求发送到URL,获取源。
  3. 正则表达源找到一些信息(可能是一系列可以连接起来形成FLV链接的元素。
  4. 下载FLV。
  5. 将FLV转换为MP3或您喜欢的任何格式。
  6. 我已经完成了第1,2,5步,它们都完全符合我的要求,但似乎对如何进行第3步缺乏明确性。有人可以打破这进一步下降了吗?例如:

    1. “XXXXXXXXX”的正则表达式
    2. 此行包含您需要的所有信息
    3. 将字符串拆分为“YYY”以获取元素列表
    4. 找到所有符合“ZZZZZ”
    5. 的元素
    6. 使用这些元素创建FLV链接
    7. 这对我来说非常有用,如果可能的话,我会喜欢在C#或PHP中提取链接的步骤或非常简单的应用程序。

2 个答案:

答案 0 :(得分:4)

以下是基于Pafy的更简洁的实现:

using System;
using System.Linq;
using HttpUtility = System.Web.HttpUtility;
using NameValueCollection = System.Collections.Specialized.NameValueCollection;
using WebClient = System.Net.WebClient;

class Program {
    public static void Main(string[] args) {
        string videoID = "2FlgVN03fNM";
        string[] itagByPriority = {"5", "6", "34", "35"};

        string videoUrl = "https://www.youtube.com/get_video_info?asv=3&el=detailpage&hl=en_US&video_id=" + videoID;
        string encodedVideo = null;

        using (var client = new WebClient()) {
            encodedVideo = client.DownloadString(videoUrl);
        }

        NameValueCollection video = HttpUtility.ParseQueryString(encodedVideo);

        string encodedStreamsCommaDelimited = video["url_encoded_fmt_stream_map"];
        string[] encodedStreams = encodedStreamsCommaDelimited.Split(new char[]{','});
        var streams = encodedStreams.Select(s => HttpUtility.ParseQueryString(s));

        var streamsByPriority = streams.OrderBy(s => Array.IndexOf(itagByPriority, s["itag"]));
        NameValueCollection preferredStream = streamsByPriority.LastOrDefault();

        if (preferredStream != null) {
            Console.WriteLine("{0}&signature={1}", preferredStream["url"], preferredStream["sig"]);
        }
    }
}

答案 1 :(得分:2)

如果您想跳过一个简单的代码示例,可以在GitHub上看到完整的源代码:https://github.com/XtrmJosh/YouTubeDownloader

我的假设非常正确,虽然花了我10个小时左右,但我终于实现了我的目标。这是一个粗略的细分:

  1. 转义字符串以确保我们不会破坏任何内容
  2. 运行一些奇特的RegEx以及什么不捕获我们正在寻找的字符串的确切区域
  3. 查找签名以及我们找到的每个网址中没有的内容(我们会发现很多内容,我们需要将它们缩小一点才能使用)
  4. 为每个网址添加我们找到的签名,否则我们会收到垃圾文件
  5. 扫描一些itags,因此我们知道与每个链接关联的文件类型 - 我想要FLV文件。
  6. 将视频名称附加到网址,然后下载。
  7. 以下是我用来获取HTML文档中所有视频网址的代码(仅适用于YouTube - 目前为止)

        public static List<string> ExtractUrls(string html)
        {
            string title = GetTitle(html);
    
            List<string> urls = new List<string>();
            string DataBlockStart = "\"url_encoded_fmt_stream_map\":\\s+\"(.+?)&";  // Marks start of Javascript Data Block
    
            html = Uri.UnescapeDataString(Regex.Match(html, DataBlockStart, RegexOptions.Singleline).Groups[1].ToString());
    
            string firstPatren = html.Substring(0, html.IndexOf('=') + 1);
            var matchs = Regex.Split(html, firstPatren);
            for (int i = 0; i < matchs.Length; i++)
                matchs[i] = firstPatren + matchs[i];
            foreach (var match in matchs)
            {
                if (!match.Contains("url=")) continue;
    
                string url = GetTxtBtwn(match, "url=", "\\u0026", 0, false);
                if (url == "") url = GetTxtBtwn(match, "url=", ",url", 0, false);
                if (url == "") url = GetTxtBtwn(match, "url=", "\",", 0, false);
    
                string sig = GetTxtBtwn(match, "sig=", "\\u0026", 0, false);
                if (sig == "") sig = GetTxtBtwn(match, "sig=", ",sig", 0, false);
                if (sig == "") sig = GetTxtBtwn(match, "sig=", "\",", 0, false);
    
                while ((url.EndsWith(",")) || (url.EndsWith(".")) || (url.EndsWith("\"")))
                    url = url.Remove(url.Length - 1, 1);
    
                while ((sig.EndsWith(",")) || (sig.EndsWith(".")) || (sig.EndsWith("\"")))
                    sig = sig.Remove(sig.Length - 1, 1);
    
                if (string.IsNullOrEmpty(url)) continue;
                if (!string.IsNullOrEmpty(sig))
                    url += "&signature=" + sig;
                urls.Add(url);
            }
    
            for (int i = 0; i < urls.Count; i++)
            {
                urls[i] += "&title=";
                urls[i] += title;
            }
    
            return urls;
        }
    
        public static string GetTitle(string RssDoc)
        {
            string str14 = GetTxtBtwn(RssDoc, "'VIDEO_TITLE': '", "'", 0, false);
            if (str14 == "") str14 = GetTxtBtwn(RssDoc, "\"title\" content=\"", "\"", 0, false);
            if (str14 == "") str14 = GetTxtBtwn(RssDoc, "&title=", "&", 0, false);
            str14 = str14.Replace(@"\", "").Replace("'", "&#39;").Replace("\"", "&quot;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("+", " ");
            return str14;
        }
    
        public static string GetTxtBtwn(string input, string start, string end, int startIndex, bool UseLastIndexOf)
        {
            int index1 = UseLastIndexOf ? input.LastIndexOf(start, startIndex) :
                                          input.IndexOf(start, startIndex);
            if (index1 == -1) return "";
            index1 += start.Length;
            int index2 = input.IndexOf(end, index1);
            if (index2 == -1) return input.Substring(index1);
            return input.Substring(index1, index2 - index1);
        }
    

    此代码(使用当前的YouTube格式)提供指向FLV文件的链接,您可以下载该文件并执行您喜欢的操作(在YouTube的服务条款中)。然后,我使用它来查找此代码提供的最高质量链接:

        public static string GetFLV(List<string> urls)
        {
            // Acquire a list of links which match the criteria for being FLV files
            List<string> flvurls = new List<string>();
            foreach (string url in urls)
            {
                string itag = Regex.Match(url, @"itag=([1-9]?[0-9]?[0-9])", RegexOptions.Singleline).Groups[1].ToString();
                int itagint;
                int.TryParse(itag, out itagint);
    
                if (itagint == 5 || itagint == 6 || itagint == 34 || itagint == 35)
                {
                    flvurls.Add(url);
                }
            }
    
            // If we didn't find any FLVs, we return a fatal error and cause a bug later on
            if (flvurls.Count == 0)
            {
                MessageBox.Show("Fatal error | iTag could not be found for FLV filetype. Please contact software vendor for assistance.");
                return "";
            }
            // If we did find some FLVs, we need to find the highest quality FLV
            else
            {
                #region findBestFLV
                foreach (string url in flvurls)
                {
                    string itag = Regex.Match(url, @"itag=([1-9]?[0-9]?[0-9])", RegexOptions.Singleline).Groups[1].ToString();
                    int itagint;
                    int.TryParse(itag, out itagint);
                    if (itagint == 35)
                    {
                        return url;
                    }
                }
                foreach (string url in flvurls)
                {
                    string itag = Regex.Match(url, @"itag=([1-9]?[0-9]?[0-9])", RegexOptions.Singleline).Groups[1].ToString();
                    int itagint;
                    int.TryParse(itag, out itagint);
                    if (itagint == 34)
                    {
                        return url;
                    }
                }
                foreach (string url in flvurls)
                {
                    string itag = Regex.Match(url, @"itag=([1-9]?[0-9]?[0-9])", RegexOptions.Singleline).Groups[1].ToString();
                    int itagint;
                    int.TryParse(itag, out itagint);
                    if (itagint == 6)
                    {
                        return url;
                    }
                }
                foreach (string url in flvurls)
                {
                    string itag = Regex.Match(url, @"itag=([1-9]?[0-9]?[0-9])", RegexOptions.Singleline).Groups[1].ToString();
                    int itagint;
                    int.TryParse(itag, out itagint);
                    if (itagint == 5)
                    {
                        return url;
                    }
                }
                #endregion
            }
            MessageBox.Show("Fatal error | Something has gone horrible wrong whilst finding the best FLV to use. Run, brave warrior, for the end is near.");
            return "";
        }
    

    请注意,这一刻非常糟糕,剩下的代码主要是我借用并略微编辑的片段,但是这一点我从头脑中写下了一些匆忙的尝试,为SOF得到了一些东西。< / p>

    希望这有助于其他人:)