.net下载优酷1080P视频

其实流程大致是:调用飞驴下载API+js解析+文件下载+调用flvBind合并这样一个流程而已_(:з」∠)_

貌似是不用太多的说明。。嗯。。

 

起先的需求是从优酷上下载一些视频
不过网络上的各种软件 甚至是优酷自己的APP 都没有提供高清视频下载的功能
而且1080P视频本身对于优酷就是一种付费功能
只好自己DIY解决了=w=

 

一些模型类

class Youku {
	public string Url;
	public string Title;
	public string Quality;
	public int Count;
	public List<YoukuFlvFile> FlvUrls = new List<YoukuFlvFile>();
}

class YoukuFlvFile {
	public string FileName;
	public string FileUrl;
	public string LocalFileName;
}


调用API

这里本来想找飞驴的开发者中心要权限来的_(:з」∠)_ 可惜被拒了..
只好截获网站自带的ajaxAPI...
这里要首先把页面地址转化为base64url 转化方法可以参考飞驴的开发文档
函数返回的是一串js代码 做进一步解析

顺带 这个api频繁调用会失效 大概服务器自己也要解析一会才有返回值...

CookieContainer cookie = new CookieContainer();
string getJS(string videoUrl) {
	string vUrl64 = Base64Url(videoUrl);
	string urlTop = "http://www.flvxz.com/?url="+vUrl64;

	//访问API
	HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://www.flvxz.com/getFlv.php?url="+vUrl64);
	req.Referer = urlTop;
	req.Method = "get";
	req.Accept = "application/javascript, */*;q=0.8";
	req.Headers.Add(HttpRequestHeader.AcceptLanguage, "zh-Hans-CN,zh-Hans;q=0.7,ja;q=0.3");
	req.UserAgent = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)";
	req.Host = "www.flvxz.com";
	//req.CookieContainer = cookie;
	HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
	StreamReader sr = new StreamReader(resp.GetResponseStream(),Encoding.UTF8);
	string result = sr.ReadToEnd();
	resp.Close();
	
	return result;
}


string Base64Url(string url) {
	url = url.Replace("://",":##");
	string vUrlBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(url));
	vUrlBase64 = vUrlBase64.Replace('+','-').Replace('=','_');
	return vUrlBase64;
}


JS解析获取flv下载地址

这个很蛋疼...返回的js是一大段eval语句 由多个flvout(html, id)函数调用组成
原本的飞驴页面则是直接执行这段js  而我们不得不用正则表达式解析...

事实上我的思路是使用Regex解析,结合SgmlReader对html格式化,最后用LINQ2XML进行抓取
算是很节省代码的一系列过程了。。

这里想仔细研究的话就自行分析DOM结构吧=w=

函数返回一个Youku实例 包含子flv文件的文件名和下载地址

Youku GetYoukuFiles(string youkuUrl) {
	Youku youku = new Youku();
	youku.Url = youkuUrl;
	string js = getJS(youkuUrl);
	Regex regex = new Regex(@"flvout\('(.+?)','(.+?)'\)");
	int idx = 0;
	foreach(Match m in regex.Matches(js)) {
		string html = string.Format("<html>{0}</html>", m.Result("$1"));
		MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(html));
		Sgml.SgmlReader r = new Sgml.SgmlReader();
		r.DocType = "html";
		r.StripDocType = true;
		r.InputStream = new StreamReader(ms);
		var xml = XElement.Load(r);
		
		var h4 = xml.XPathSelectElements("./div/div/h4").FirstOrDefault();
		if (h4 != null) {
			youku.Title = h4.Value;
		}
		string qua = xml.Elements("span").Skip(1).First().Value;
		if (qua.Contains("1080P")) {
			string count = xml.Elements("span").Skip(2).First().Value;
			youku.Quality = qua;
			youku.Count = Convert.ToInt32(count);
			
			var items = xml.Elements("a").Where(elem=> {
				var attrRel = elem.Attribute("rel");
				return attrRel != null && attrRel.Value=="noreferrer"; 
			}).Select(elem=>new {title = elem.Value, href = elem.Attribute("href").Value});
			
			foreach(var item in items) {
				var f = new YoukuFlvFile();
				f.FileName = item.title;
				f.FileUrl = item.href;
				youku.FlvUrls.Add(f);
			}
		}
		idx++;
	}
	
	return youku;
}


下载文件

直接WebClient的干活 它的好处是如果出现exception会自动删除下载一半的文件...
如果想支持断点续传请自己编写更多文字_(:з」∠)_

void Download0(Youku m) {
	var client = new WebClient();
	if(m.FlvUrls.Count>0) {
		string dir = Path.Combine(downloadDir, m.Title);
		if (!Directory.Exists(dir)) {
			Directory.CreateDirectory(dir);
		}
		
		//下载
		foreach(var file in m.FlvUrls) {
			file.LocalFileName = Path.Combine(dir, file.FileName);
			if (!File.Exists(file.LocalFileName)) {
				client.DownloadFile(file.FileUrl, file.LocalFileName);
				Console.WriteLine(file.FileName+" 下载完毕");
			} else {
				Console.WriteLine(file.FileName+" 文件已存在");
			}
		}
	}
}


合并flv

直接用flvBind命令行工具 省时省力

原来想用ffmpeg直接转成mp4来的 我已经疯了=w=
因为windows上使用管道的恶心程度和参数的问题只好放弃...
如果知道怎么调教ffmpeg解决“多个x264流合并而且不二次编码”的旷世难题一定教教我_(:з」∠)_ 简直虐心

void Combine0(Youku m) {
	ProcessStartInfo ps = new ProcessStartInfo(@"E:\Program files\ffmpeg-win64\bin\FlvBind.exe");
	ps.Arguments = string.Join(" ",
		new[]{ m.Title+".flv"}
		.Concat(m.FlvUrls.Select(f=>f.LocalFileName))
		.Select(str=>"\""+str+"\"")
	);
	ps.WorkingDirectory = downloadDir;
	var p = Process.Start(ps);
	p.WaitForExit();
	Console.WriteLine(m.Title+" 合并完成");
}

 

最后把上面的代码连上即可=w=

 

void Main()
{	
	string url = "http://v.youku.com/v_show/id_XNzU4OTM0Njg0.html";
	for(int t=0;t<5;t++) {
		var m = GetYoukuFiles(url);
		if (m.FlvUrls.Count>0) {
			Download0(m);
			if (!File.Exists(Path.Combine(downloadDir, m.Title+".flv"))) {
				Combine0(m);
			}
		} else {
			Console.WriteLine("获取失败...3秒后重试");
			Thread.Sleep(3000);
		}
	}
}

string downloadDir = @"D:\2014Cj";


以上代码可以在win8x64 .net4.5  LINQPAD 4.48中正常执行

SgmlReader可以在csdn下载频道中找到

flvBind可以自行搜索 是一个很迷你的视频处理工具

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。