大家好,又见面了,我是你们的朋友全栈君。
最简单的办法,就是利用各种网盘搜索,找到网盘的分享地址,转存到自己的网盘,然后下载。这样就避免了从在线视频网站直接下载,而且常常清晰度比较高。
如果网盘找不到,第二种办法是利用一些在线视频的解析网站。只要把视频的网址输进去,就能解析出下载地址,也很简单。大的视频网站如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=1280×720 /foo/bar/index.m3u8
这个需要在Network页里随便找个视频片断的网址,比如是https://foo.com/1.ts,然后拼接出完整的m3u8网址https://foo.com/foo/bar/index.m3u8,手工下载,才得到完整的播放列表。
得到播放列表后,首先用程序转成便于下载工具导入的列表文件:
代码语言:javascript复制 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这个插件,写段程序生成它专用的下载列表:
代码语言:javascript复制var lines = File.ReadAllLines(@“C:foo.txt");//下载列表文件,一行一个url
代码语言:javascript复制 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("&", "&").Replace(">", ">").Replace("<", "<").Replace(""", """);
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的下载速度不快,所以这个方法我也不常用,一般是先用其他下载工具下载完视频文件后,再用下面的程序给文件重命名:
代码语言:javascript复制 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文件,然后用下面的程序解密:
代码语言:javascript复制 private void decrypt()
{
var folder = @"C:foo";
byte[] encryptionKey = File.ReadAllBytes(@"C:fookey.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:fooerror1.txt", sberror.ToString());
MessageBox.Show("error");
}
代码语言:javascript复制 }
值得注意的是某些加密视频中夹有一段不加密的广告。我一般是手工删除这些广告后再解密。
最后一步是合并下载到的视频文件。我一般是用个dos批处理文件来处理:
代码语言:javascript复制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合并时有时会出错。我也没有什么好办法 ,只能将视频拆成两三段,相当于上下或者上中下集,分段数不太多的话 ,尚可接受。
大致的下载方法就这些。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/154252.html原文链接:https://javaforall.cn