分析过后,我们接着来做一下代码实现
三、获取流程实现
近期正巧看到了木鱼在自己博客里发布的一个HTTP客户端库,困扰于原生HttpWebRequest的我立马就下来用了用,效果果然不错,所以本项目的HTTP请求就由
FSLib.Network 类库来完成,语法差别不大,不太懂的地方可以回复。
添加类库可以使用nuget:
Install-Package network.fishlee.net
下面来写通过展示地址来获得下载连接的方法:
private async void GetDownLoadUrl(string fileUrl) { //建立HTTP客户端 var client = new HttpClient(); //用于接收验证码 StringBuilder Result; //验证码的字符数组 byte[] bytes; //用于接收下载链接 string downPath = string.Empty; //通过正则匹配到链接中的 fileid int id = Convert.ToInt32(Extract(fileUrl, "\\d{7,}")); //有时会出现一级域名为ymhwp的情况,这里先做一下替换,以防不测 fileUrl = fileUrl.Replace("ymhwp", "yimuhe"); //创建展示页面请求 var filecontext = client.Create<string>(HttpMethod.Get, fileUrl); //发送请求 await filecontext.SendTask(); if (filecontext.IsValid())//如果请求成功 { //替换链接中的fil为down,使其成为下载页面地址 fileUrl = fileUrl.Replace("file", "down"); //创建下载页面请求 var downcontext = client.Create<string>(HttpMethod.Get, fileUrl); await downcontext.SendTask(); if (downcontext.IsValid()) { //设置初始返回值为0,表示验证码输入错误,即识别失败 int response = 0; while (response == 0)//循环识别,直到识别成功 { //创建验证码图片请求 var vcode = client.Create<Byte[]>(HttpMethod.Get, "http://www.yimuhe.com/n_downcode.php"); await vcode.SendTask(); if (vcode.IsValid()) { //将获取到的验证码图片存入字节数组中 bytes = vcode.Result; Result = new StringBuilder('\0', 256); //识别验证码 GetVcodeFromBuffer(1, bytes, bytes.Length, Result); //创建检验验证码请求 var resp = client.Create<string>(HttpMethod.Post, "http://www.yimuhe.com/n_downcode.php", data: "action=yz&id=" + id + "&code=" + Result); await resp.SendTask(); if (resp.IsValid()) { //返回验证码校验值、成功为1失败为0 response = Convert.ToInt32(resp.Result); } } } //创建获取下载地址请求 var h1 = client.Create<string>(HttpMethod.Post, "http://www.yimuhe.com/n_dd.php?file_id=" + id + "&ser=99", refer: "http://www.yimuhe.com/down-2546737.html", data: id.ToString()); await h1.SendTask(); if (h1.IsValid()) { //通过HtmlAgilityPack库完成html解析,获得下载地址 HtmlDocument html = new HtmlDocument(); html.LoadHtml(h1.Result); downPath = html.GetElementbyId("downs").Attributes["href"].Value; tBAfter.AppendText(downPath + NewLine); } } } }
通过以上方法即可实现单个文件下载地址的获取。
四、批量获取实现
我的批量实现思路为将要获取的链接加入一个队列当中,线程从队头移出数据一条进行地址获取,获取成功不进行操作,失败则将地址添回到队尾。循环获取直到队列为空。另一个队列储存正在处理的数据,仅当两个线程均为空时才会陆续结束所有线程。线程执行的方法在上边的方法基础上又做了一些修改。
具体实现代码如下:
private async void GetDownLoadUrl() { //当链接队列和正在处理队列存在不为空时,循环执行以下代码 while (_pathList.Count > 0 || _pathReady.Count > 0) { //当链接队列不为空时 if (_pathList.Count > 0) { //从队头取出一条数据 string fileUrl = _pathList[0]; _pathList.RemoveAt(0); _pathReady.Add(fileUrl); //建立HTTP客户端 var client = new HttpClient(); //用于接收验证码 StringBuilder Result; //验证码的字符数组 byte[] bytes; //用于接收下载链接 string downPath = string.Empty; //通过正则匹配到链接中的 fileid int id = Convert.ToInt32(Extract(fileUrl, "\\d{7,}")); //有时会出现一级域名为ymhwp的情况,这里先做一下替换,以防不测 fileUrl = fileUrl.Replace("ymhwp", "yimuhe"); //创建展示页面请求 var filecontext = client.Create<string>(HttpMethod.Get, fileUrl); //发送请求 await filecontext.SendTask(); if (filecontext.IsValid())//如果请求成功 { //替换链接中的fil为down,使其成为下载页面地址 fileUrl = fileUrl.Replace("file", "down"); //创建下载页面请求 var downcontext = client.Create<string>(HttpMethod.Get, fileUrl); await downcontext.SendTask(); if (downcontext.IsValid()) { //设置初始返回值为0,表示验证码输入错误,即识别失败 int response = 0; while (response == 0)//循环识别,直到识别成功 { //创建验证码图片请求 var vcode = client.Create<Byte[]>(HttpMethod.Get, "http://www.yimuhe.com/n_downcode.php"); await vcode.SendTask(); if (vcode.IsValid()) { //将获取到的验证码图片存入字节数组中 bytes = vcode.Result; Result = new StringBuilder('\0', 256); //识别验证码 GetVcodeFromBuffer(1, bytes, bytes.Length, Result); //创建检验验证码请求 var resp = client.Create<string>(HttpMethod.Post, "http://www.yimuhe.com/n_downcode.php", data: "action=yz&id=" + id + "&code=" + Result); await resp.SendTask(); if (resp.IsValid()) { //返回验证码校验值、成功为1失败为0 response = Convert.ToInt32(resp.Result); } } } //创建获取下载地址请求 var h1 = client.Create<string>(HttpMethod.Post, "http://www.yimuhe.com/n_dd.php?file_id=" + id + "&ser=99", refer: "http://www.yimuhe.com/down-2546737.html", data: id.ToString()); await h1.SendTask(); if (h1.IsValid()) { //通过HtmlAgilityPack库完成html解析,获得下载地址 HtmlDocument html = new HtmlDocument(); html.LoadHtml(h1.Result); downPath = html.GetElementbyId("downs").Attributes["href"].Value; //将获取到的地址显示到界面 tBAfter.AppendText(downPath + NewLine); } } } //如果downPath为空,则请求失败 if (string.IsNullOrWhiteSpace(downPath)) { //将请求链接添回队尾 _pathList.Add(path); } //处理完毕,移出当前处理队列 _pathReady.Remove(path); } } }