如何获取 YouTube 视频的直接网址

IT技术 javascript download youtube
2021-02-23 15:20:14

当前有关制作自己的 youtube 视频下载器的所有教程都已过时。视频信息中的整个令牌插入不起作用,使用 javascript 方法也不起作用。有没有人知道目前无需下载其他人的程序即可执行此操作的方法?我只是想知道要进行的方法,以便我可以编写自己的程序(为了好玩:D)

提前致谢!

3个回答

截至 2018 年 1 月 1 日,下面描述的旧技术似乎不能可靠地工作。Youtube 的页内变量结构似乎发生了变化,我一直无法弄清楚更新的版本。

这是一个更新的(2017 年 6 月)版本,可直接从任何浏览器中可用的开发工具控制台运行。目前应该适用于任何 Youtube 媒体类型,包括最多 4k(如果可用)。

https://gist.github.com/geuis/8b1b2ea57d7f9a9ae22f80d4fbf5b97f

// ES6 version
const videoUrls = ytplayer.config.args.adaptive_fmts
  .split(',')
  .map(item => item
    .split('&')
    .reduce((prev, curr) => (curr = curr.split('='),
      Object.assign(prev, {[curr[0]]: decodeURIComponent(curr[1])})
    ), {})
  )
  .reduce((prev, curr) => Object.assign(prev, {
    [curr.quality_label || curr.type]: curr
  }), {});

console.log(videoUrls);

// ES5 version
var videoUrls = ytplayer.config.args.adaptive_fmts
  .split(',')
  .map(function (item) {
    return item
      .split('&')
      .reduce(function (prev, curr) {
        curr = curr.split('=');
        return Object.assign(prev, {[curr[0]]: decodeURIComponent(curr[1])})
      }, {});
  })
  .reduce(function (prev, curr) {
    return Object.assign(prev, {
      [curr.quality_label || curr.type]: curr
    });
  }, {});

console.log(videoUrls);

https://www.youtube.com/watch?v=9bZkp7q19f0 的示例输出

{
  "1080p": {
    "itag": "248",
    "xtags": "",
    "lmt": "1440215955569849",
    "url": "https://r16---sn-n4v7kn7r.c.youtube.com/videoplayback?itag=248&keepalive=ye…2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csc%2Csource%2Cexpire&mt=1498245944",
    "type": "video/webm;+codecs=\"vp9\"",
    "bitrate": "1733724",
    "index": "243-1977",
    "size": "1920x1080",
    "projection_type": "1",
    "fps": "30",
    "clen": "31192903",
    "init": "0-242",
    "quality_label": "1080p"
  },
  "720p": {
    "itag": "247",
    "xtags": "",
    "lmt": "1440215905109639",
    "url": "https://r16---sn-n4v7kn7r.c.youtube.com/videoplayback?itag=247&keepalive=ye…2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csc%2Csource%2Cexpire&mt=1498245944",
    "type": "video/webm;+codecs=\"vp9\"",
    "bitrate": "726076",
    "index": "243-1933",
    "size": "1280x720",
    "projection_type": "1",
    "fps": "30",
    "clen": "15801933",
    "init": "0-242",
    "quality_label": "720p"
  },
  "480p": {
    "itag": "244",
    "xtags": "",
    "lmt": "1440215890236689",
    "url": "https://r16---sn-n4v7kn7r.c.youtube.com/videoplayback?itag=244&keepalive=ye…2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csc%2Csource%2Cexpire&mt=1498245944",
    "type": "video/webm;+codecs=\"vp9\"",
    "bitrate": "396541",
    "index": "243-1933",
    "size": "854x480",
    "projection_type": "1",
    "fps": "30",
    "clen": "7928237",
    "init": "0-242",
    "quality_label": "480p"
  },
  "360p": {
    "itag": "243",
    "xtags": "",
    "lmt": "1440215888783441",
    "url": "https://r16---sn-n4v7kn7r.c.youtube.com/videoplayback?itag=243&keepalive=ye…2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csc%2Csource%2Cexpire&mt=1498245944",
    "type": "video/webm;+codecs=\"vp9\"",
    "bitrate": "223695",
    "index": "243-1933",
    "size": "640x360",
    "projection_type": "1",
    "fps": "30",
    "clen": "5127362",
    "init": "0-242",
    "quality_label": "360p"
  },
  "240p": {
    "itag": "242",
    "xtags": "",
    "lmt": "1440215900971640",
    "url": "https://r16---sn-n4v7kn7r.c.youtube.com/videoplayback?itag=242&keepalive=ye…2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csc%2Csource%2Cexpire&mt=1498245944",
    "type": "video/webm;+codecs=\"vp9\"",
    "bitrate": "113952",
    "index": "242-1931",
    "size": "426x240",
    "projection_type": "1",
    "fps": "30",
    "clen": "2597162",
    "init": "0-241",
    "quality_label": "240p"
  },
  "144p": {
    "itag": "278",
    "xtags": "",
    "lmt": "1440215900119192",
    "url": "https://r16---sn-n4v7kn7r.c.youtube.com/videoplayback?itag=278&keepalive=ye…2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csc%2Csource%2Cexpire&mt=1498245944",
    "type": "video/webm;+codecs=\"vp9\"",
    "bitrate": "60303",
    "index": "242-1930",
    "size": "256x144",
    "projection_type": "1",
    "fps": "15",
    "clen": "1798744",
    "init": "0-241",
    "quality_label": "144p"
  },
  "audio/mp4;+codecs=\"mp4a.40.2\"": {
    "bitrate": "128266",
    "itag": "140",
    "xtags": "",
    "lmt": "1440578358539132",
    "index": "592-1271",
    "clen": "8482615",
    "projection_type": "1",
    "url": "https://r16---sn-n4v7kn7r.c.youtube.com/videoplayback?itag=140&keepalive=ye…2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csc%2Csource%2Cexpire&mt=1498245944",
    "type": "audio/mp4;+codecs=\"mp4a.40.2\"",
    "init": "0-591"
  },
  "audio/webm;+codecs=\"vorbis\"": {
    "bitrate": "118499",
    "itag": "171",
    "xtags": "",
    "lmt": "1440215938192462",
    "index": "4452-5366",
    "clen": "6383456",
    "projection_type": "1",
    "url": "https://r16---sn-n4v7kn7r.c.youtube.com/videoplayback?itag=171&keepalive=ye…2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csc%2Csource%2Cexpire&mt=1498245944",
    "type": "audio/webm;+codecs=\"vorbis\"",
    "init": "0-4451"
  },
  "audio/webm;+codecs=\"opus\"": {
    "bitrate": "154966",
    "itag": "251",
    "xtags": "",
    "lmt": "1440215889283443",
    "index": "272-1186",
    "clen": "9526605",
    "projection_type": "1",
    "url": "https://r16---sn-n4v7kn7r.c.youtube.com/videoplayback?itag=251&keepalive=ye…2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csc%2Csource%2Cexpire&mt=1498245944",
    "type": "audio/webm;+codecs=\"opus\"",
    "init": "0-271"
  }
}
是的,因为您无法访问移动 Safari 中的开发工具,除非您通过 USB 电缆连接到 Mac,并打开桌面 Safari 及其开发工具。在这种情况下,它将起作用。
2021-05-05 15:20:14
@Anthony 如果你用你的代码创建一个代码笔会更容易。将使协作更容易。
2021-05-08 15:20:14
@lukejacksonn 不在常规浏览器中。加载到 iframe(在本例中为 youtube.com)的任何站点都被沙盒化。这是为了防止跨站点脚本等安全问题。因此,基本上,您几乎无法访问 iframe 中页面的 javascript 环境。您必须将自己的脚本注入 iframe 页面才能进行通信。你不能在 youtube.com 上这样做
2021-05-13 15:20:14
@Anthony 这实际上要归功于@MohammadDayyan 指出未列出 4k 视频。我已经对 js 对象有点熟悉了,重新检查它让我发现adaptive_fmts.
2021-05-16 15:20:14
与第一条评论相同的答案。除非您将 youtube 加载到 WKWebKit 或 UIWebKit 等 3rd 方浏览器中,您可以在其中注入 javascript,或者如果您正在开发允许您执行相同操作的浏览器扩展,您只能ytplayer从控制台访问该对象。或者,如果您抓取页面,则可以解析出包含它的脚本元素。
2021-05-16 15:20:14

截至今天 15/06/2012 真的很简单;但你必须注意未来的变化。在这里(在 Javascript 中)

try{
    var urls = document.body.innerHTML.match(/"url_encoded_fmt_stream_map": "url=([^"]+)/)[1]
    urls = decodeURIComponent(urls).replace(/\\u0026/g,'&')
    urls = urls.replace(/&quality.+?(?=,url)/g,'');;
    urls = urls.split(',url=')
    // urls is an array of all the possible qualities
    // To download one you could use something like:
    // document.location = urls[0]
    // The first one is usually in the highest quality available
} catch(e){
    console.error("Youtube may have changed its API")
}
它仍然存在,只是url=位置发生了变化......需要正则表达式专家:)
2021-05-04 15:20:14
于 2012 年 12 月 17 日试用,但无法正常工作。YT最近换了个样子...
2021-05-16 15:20:14

为什么要重新发明轮子?使用 Rapidleech 脚本!

顺便说一句,如果您仍然需要重新发明轮子,这里是 Rapidleech 的 Youtube 插件的源代码(它具有高度可读性:


class youtube_com extends DownloadClass {

    /*
    Some blah blah about the age verification and erroneous URLs
    $fmt is quality/format number and is an integer
   */
    public function Download($link) {
        $this->fmts = array(38,37,22,45,35,44,34,43,18,5,17);
        $yt_fmt = empty($_REQUEST['yt_fmt']) ? '' : $_REQUEST['yt_fmt'];
        $this->fmturlmaps = $this->GetVideosArr($fmt_url_maps);

        if (empty($yt_fmt) && !isset($_GET["audl"])) return $this->QSelector($link);
        elseif (isset($_REQUEST['ytube_mp4']) && $_REQUEST['ytube_mp4'] == 'on' && !empty($yt_fmt)) {
            //look for and download the highest quality we can find?
            if ($yt_fmt == 'highest') {
                foreach ($this->fmts as $fmt) {
                    if (array_key_exists($fmt, $this->fmturlmaps)) {
                        $furl = $this->fmturlmaps[$fmt];
                        break;
                    }
                }
            } else { //get the format the user specified (making sure it actually exists)
                if (!$furl = $this->fmturlmaps[$yt_fmt]) html_error ('Specified video format not found');
                $fmt = $yt_fmt;
            }
        } else { //just get the one Youtube plays by default (in some cases it could also be the highest quality format)
            $fmt = key($this->fmturlmaps);
            $furl = $this->fmturlmaps[$fmt];
        }

        if (preg_match ('%^5|34|35$%', $fmt)) $ext = '.flv';
        elseif (preg_match ('%^17$%', $fmt)) $ext = '.3gp';
        elseif (preg_match ('%^18|22|37|38$%', $fmt)) $ext = '.mp4';
        elseif (preg_match ('%^43|44|45$%', $fmt)) $ext = '.webm';
        else $ext = '.flv';

        if (!preg_match('#<title>(.*)\s+-\sYouTube[\r|\n|\t|\s]*</title>#Us', $this->page, $title)) html_error('No video title found! Download halted.');
        if (!preg_match ('/video_id=(.+?)(\\\|"|&|(\\\u0026))/', $this->page, $video_id)) html_error('Video id not found.');

        $FileName = str_replace (Array ("\\", "/", ":", "*", "?", "\"", "<", ">", "|"), "_", html_entity_decode(trim($title[1]), ENT_QUOTES)) . "-[{$video_id[1]}][f$fmt]$ext";

        if (stristr($furl, '|')) {
            $u_arr = explode('|', $furl);
            $furl = preg_replace('#://([^/]+)#', "://".$u_arr[2], $u_arr[0]);
        }
        if (isset($_REQUEST['ytdirect']) && $_REQUEST['ytdirect'] == 'on')
        {
            echo "<br /><br /><h4><a style='color:yellow' href='" . urldecode($furl) . "'>Click here or copy the link to your download manager to download</a></h4>";
            echo "<input name='dlurl' style='width: 1000px; border: 1px solid #55AAFF; background-color: #FFFFFF; padding:3px' value='" . urldecode($furl) . "' onclick='javascript:this.select();' readonly></input>";
        }
        else
        {
            $this->RedirectDownload (urldecode($furl), $FileName, $this->cookie, 0, 0, $FileName);
        }
    }