【问题标题】:Acquire FLV URL from YouTube从 YouTube 获取 FLV URL
【发布时间】:2014-02-15 19:56:45
【问题描述】:

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

这是我目前所拥有的:

  1. 向最终用户请求链接(例如 www.youtube.com/watch?v=2FlgVN03fNM)
  2. 向 URL 发送 HTTP 请求,获取源。
  3. 对源进行正则表达式以查找一些信息(可能是一系列可以连接起来形成 FLV 链接的元素。
  4. 下载 FLV。
  5. 将 FLV 转换为 MP3 或您喜欢的任何格式。

我已经完成了第 1、2、5 步,而且它们都完全按照我的意愿去做,但似乎对如何进行第 3 步还不清楚。有人可以打破这个再往下一点?示例:

  1. “XXXXXXXXX”的正则表达式
  2. 此行包含您需要的所有信息
  3. 将字符串按“YYY”拆分以获得元素列表
  4. 查找所有匹配“ZZZZZ”的元素
  5. 使用这些元素创建 FLV 链接

这对我来说非常有用,如果可能的话,我会喜欢使用 C# 或 PHP 提取链接的步骤或非常简单的应用程序。

【问题讨论】:

  • 您需要一个 HTML 解析器。 htmlagilitypack.codeplex.com
  • 这真的不能用RegEx实现吗?或者更好的是,在 .NET 中使用字符串操作?
  • 你能明确一些信息吗?
  • 不完全确定还有什么可以更清楚 - 实际上这是我缺乏的细节,我想我要找的是以前做过这个的人,或者至少非常了解视频网站,知道如何完成。我会尽快添加一些信息以及一些我自发布以来一直在研究的 C#...

标签: c# regex youtube download


【解决方案1】:

这里有一个基于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"]);
        }
    }
}

【讨论】:

  • 你的回答确实比我的要简洁很多,但我觉得同时理解起来有点困难,因为嵌套的方法很广泛(我认为这是术语-preferredStream = ~~~对我来说有点长。无论如何我都会投赞成票,但除非出现其他问题,否则我会自己回答。谢谢!
  • 这通常称为“方法链”。我喜欢这种风格,但我同意由于缺少变量名而难以理解。我已将其转换为更传统的风格,可能更容易理解。
【解决方案2】:

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

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

  1. 转义字符串以确保我们不会破坏任何内容
  2. 运行一些花哨的 RegEx 和什么不捕获我们正在寻找的字符串的确切区域
  3. 在我们找到的每个 URL 中查找签名和未包含的内容(我们会找到很多,我们需要将它们缩小一点,然后才能使用它们)
  4. 将我们为每个 URL 找到的签名添加到它,否则我们会得到垃圾文件
  5. 扫描一些 itag,这样我们就知道每个链接关联的文件类型 - 我想要 FLV 文件。
  6. 将视频名称附加到 URL,然后下载。

这是我用来获取 HTML 文档中所有视频 URL 的代码(仅限 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 的 TOS 内)。然后我用它从这段代码提供的链接中找到最高质量的链接:

    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 "";
    }

请注意,它现在非常杂乱无章,其余的代码大部分是我借用和稍微编辑的 sn-ps,但是我在匆忙尝试为 SOF 整理一些东西时从脑海中写下了这段代码.

希望这对其他人有帮助:)

【讨论】:

    猜你喜欢
    • 2011-11-22
    • 1970-01-01
    • 1970-01-01
    • 2011-12-03
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-20
    相关资源
    最近更新 更多