• .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频繁调用会失效 大概server自己也要解析一会才有返回值...

    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 filesffmpeg-win64inFlvBind.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能够自行搜索 是一个非常迷你的视频处理工具

  • 相关阅读:
    Linux下的tar压缩解压缩命令详解
    python学习笔记-day9-2【面向对象】
    python学习笔记-day9-1【发送邮件模块 yagmail】
    python学习笔记-day8-4-【python 内置函数补充:zip,map,filter】
    python学习笔记-day8-3-【python 网络请求及requests模块】
    python学习笔记-day8-2-【python 异常处理 try except】
    python学习笔记-day8-1-【python flask接口开发】
    day9-Python学习笔记(二十一)单元测试
    day9-Python学习笔记(二十)数据库备份,修改父类的方法
    day8-Python学习笔记(十八)面向对象,self,私有,属性方法
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4250161.html
Copyright © 2020-2023  润新知