首页 > 技术文章 > 在线视频的5种下载办法

badnumber 2021-09-04 10:19 原文

最简单的办法,就是利用各种网盘搜索,找到网盘的分享地址,转存到自己的网盘,然后下载。这样就避免了从在线视频网站直接下载,而且常常清晰度比较高。

如果网盘找不到,第二种办法是利用一些在线视频的解析网站。只要把视频的网址输进去,就能解析出下载地址,也很简单。大的视频网站如B站,优酷等都有解析网站。不过,现在的视频网站经常调整,所以解析也常常失效。

第三种办法是利用某些工具。我比较常用的是you-get和youtube-dl,都是用python编写的,开放源代码,可以根据自己的需求修改。youtube-dl的功能更为强大,支持的网站也更多。但某些功能做的太繁琐,用起来不太方便,比如下载字幕,挑选清晰度等。you-get在这些方面比较方便些,同时程序较小,改起来也方便些。

第四种办法是直接查看网页的源代码,找到下载地址。某些视频网站如西瓜视频可以这样做。

第五种办法是设法获取到m3u8下载列表,然后再下载。如果得到了m3u8的网址,可以用某些m3u8专用下载工具下载,试过一两种,感觉都不理想,不是速度太慢,就是操作繁琐。

可以用youtube-dl直接下载:youtube-dl <m3u8的url>。方便是方便,但因为实质是利用ffmpeg来下载(那些m3u8专用下载工具估计有的也是这样的),大概是单线程的,一是速度比较慢,二是如果出错,又得重来。所以我一般都是手工下载m3u8文件后再用下载工具如Internet Download Manager之类下载视频文件,然后再用ffmpeg拼成单个文件。

手工下载了m3u8文件,如果想偷懒,可以直接在命令行输入ffmpeg -protocol_whitelist file,http,https,tcp,tls,crypto -i index.m3u8 -c copy my_movie.ts下载,优缺点和上面用youtube-dl下载m3u8是一样的。

手工操作的话,第一步是下载m3u8文件。有个还不错的工具,chrome浏览器的插件hls downloader,可以自动捕捉到m3u8的网址,用起来比较方便。有些网址用这个工具捕捉不到,需要点击chrome浏览器的Network页,然后找出含有m3u8的网址,再手工下载。个别的网站还需要研究它的js源码,找到m3u8的内容。比如某网站在Network页里找不到m3u8,分析其js,找到了一个函数foo(e.data),e.data里就是m3u8的内容。于是在该函数上加上断点,刷新页面,到断点停下来时,在Console里输入console.log(e.data); 就打印出了m3u8。

下载到的m3u8文件,主要有两种。一种有完整的播放列表,一种只有一个m3u8的地址:

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1000000,RESOLUTION=1280x720
/foo/bar/index.m3u8

这个需要在Network页里随便找个视频片断的网址,比如是https://foo.com/1.ts,然后拼接出完整的m3u8网址https://foo.com/foo/bar/index.m3u8,手工下载,才得到完整的播放列表。

得到播放列表后,首先用程序转成便于下载工具导入的列表文件:

        private void m3u8toList()
        {
            StringBuilder sb = new StringBuilder();
            var lines = File.ReadAllLines(@"C:\index.m3u8");
            foreach (string line in lines)
            {
                if (line.IndexOf("#") < 0)
                {
                    sb.AppendLine(line);
                }
            }
            File.WriteAllText(@"C:\foo.txt", sb.ToString());
        }

播放列表里的视频文件名大致有两种,一种是有规律的,如foo_001.ts, foo_002.ts等,这种相对方便一些,一种没有规律,比如N3Atb.ts,2BjMl.ts等,这种会给下一步的合并文件带来困难(如果直接用ffmpeg下载没有这个问题,但手工操作就有问题)。一个办法是利用DownthemAll这个插件,写段程序生成它专用的下载列表:

var lines = File.ReadAllLines(@“C:\foo.txt");//下载列表文件,一行一个url
 StringBuilder sb = new StringBuilder(); 
int count = 1;
sb.AppendLine(
"<?xml version=\"1.0\"?>");
sb.AppendLine(
"<metalink xmlns=\"urn:ietf:params:xml:ns:metalink\" version=\"4.0\" a0:version=\"3.0.8\" xmlns:a0=\"http://www.downthemall.net/properties#\">");
sb.AppendLine(
"<generator>DownThemAll!/3.0</generator>");
var date = (Int64)(DateTime.UtcNow .Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)) .TotalMilliseconds);
var utcString = DateTime.UtcNow.ToString("r");
sb.AppendLine(
"<published>" + utcString + "</published>");
foreach (var line in lines)
{
string serial = String.Format("{0:0000}", count);
string url = line.Replace("&", "&amp;").Replace(">", "&gt;").Replace("<", "&lt;").Replace("\"", "&quot;");
sb.AppendLine(
"<file name=\"" + serial + ".ts" + "\" a0:num=\"442\" a0:startDate=\"" + date.ToString() + "\" >");
sb.AppendLine(
"<url priority=\"100\" a0:usable=\"" + url + "\">" + url + "</url>");
sb.AppendLine(
"</file>");
date
= date + 4;
count
++;
}
sb.AppendLine(
"</metalink>");
File.WriteAllText(
@"C:\downloadList.meta4", sb.ToString());

不过因为downthemall的下载速度不快,所以这个方法我也不常用,一般是先用其他下载工具下载完视频文件后,再用下面的程序给文件重命名:

        private void renameDownloads()
        {
            var lines = File.ReadAllLines(@"C:\foo.txt");
            int count = 1;
            SortedList<string, string> mapping = new SortedList<string, string>();
            int idx = 0;
            foreach (var line in lines)
            {
                idx = line.LastIndexOf("/") + 1;
                mapping.Add(line.Substring(idx), string.Format("{0:0000}", count) + ".ts");
                count++;
            }
              var files = Directory.GetFiles(folder, "*.ts");
              foreach (var file in files)
              {
                 string fileName = Path.GetFileName(file);
                 File.Move(file, Path.Combine(folder, mapping[fileName]));
              }
        }

某些m3u8里的视频文件是加密的,下载的ts文件用播放器无法直接打开。一般是文件中有段:

#EXT-X-KEY:METHOD=AES-128,URI="https://foo.com/key.key"

这种需要先从这个网址手工下载key.key文件,然后用下面的程序解密:

        private void decrypt()
        {
            var folder = @"C:\foo";
            byte[] encryptionKey = File.ReadAllBytes(@"C:\foo\key.key");

            StringBuilder sberror = new StringBuilder();
            var files = Directory.GetFiles(folder, "*.ts");
            for (int i = 0; i < files.Length; i++)
            {
                string fileName = Path.GetFileName(files[i]);
                string outputFile = Path.Combine(folder, Path.GetFileNameWithoutExtension(fileName) + ".mp4");
                using (FileStream outputFileStream = new FileStream(outputFile, FileMode.Create))
                {
                    byte[] encryptionIV = new byte[16];
                    using (FileStream inputFileStream = new FileStream(files[i], FileMode.Open))
                    {
                        try
                        {
                            using (var aes = new AesManaged { Key = encryptionKey, IV = encryptionIV, Mode = CipherMode.CBC })
                            using (var encryptor = aes.CreateDecryptor())
                            using (var cryptoStream = new CryptoStream(inputFileStream, encryptor, CryptoStreamMode.Read))
                            {
                                cryptoStream.CopyTo(outputFileStream);
                            }
                        }
                        catch (Exception ex)
                        {
                            sberror.AppendLine(fileName);
                        }
                    }
                }
            }
            if (sberror.Length > 0)
            {
                File.WriteAllText(@"C:\foo\error1.txt", sberror.ToString());
MessageBox.Show("error");
}
        }

值得注意的是某些加密视频中夹有一段不加密的广告。我一般是手工删除这些广告后再解密。

最后一步是合并下载到的视频文件。我一般是用个dos批处理文件来处理:

for %%i in (*.ts) do echo file '%%i'>> t1.txt
pause
ffmpeg -f concat -safe 0 -i t1.txt -c copy final.mp4

pause的作用是生成文件列表后,有个手工调整的机会。某些情况下,比如有1.ts,2.ts......10.ts文件,正确的次序是从1到10,但是这个批处理有可能将10.ts排在1.ts的后面,所以需要手工调整。

需要注意的是某些m3u8文件中有EXT-X-DISCONTINUITY标记,这时用ffmpeg合并时有时会出错。我也没有什么好办法 ,只能将视频拆成两三段,相当于上下或者上中下集,分段数不太多的话 ,尚可接受。

大致的下载方法就这些。

推荐阅读