• 极客学院职业路径图课程视频下载-爬虫


    一、序言

      最近看了极客学院的视频教程,相当不错,渴望把视频下载到本地。手动下载耗时耗力,因而决定研究一番,写一程序自动下载,终于小有成果!有图为证:

    二、技术难点

      既然要实现自动下载,免不了要爬取极客学院的页面获取视频地址。经尝试,可以发现大部分视频观看是需要登录,并且是会员。于是所要解决的要点有:

      1、拥有会员

      2、模拟登录

      3、解析html

      4、继续下载(可能出现异常情况下)

    三、实现

      (1)、要获取极客学院会员相当简单(如果已经是会员用户,可跳过此步骤),利用邀请好友获取30天体验,如下图:(30天足够把所有的视频下载完毕)

      

      (2)、会员问题解决了,最大的难点就是模拟登录了。细心的人就会发现,极客学院提供了一个ajax方式登录的接口!如下图:

      

      当我们点击登录的时候,会发起一个ajax请求,通过抓包工具,我们可以获取到登录地址:http://passport.jikexueyuan.com/submit/login?is_ajax=1,验证码地址:http://passport.jikexueyuan.com/sso/verify

      “万事俱备只欠东风”,地址都知道了,还怕登录不了么?如下是本人最终实现登录效果:

      

     1 /// <summary>
     2 /// 获取验证码
     3 /// </summary>
     4 void GetVerifyCode()
     5 {
     6     VerifyCode.Source = null;
     7 
     8     // 1. 先请求登录地址,获取到当前用户的会话cookie
     9     HttpResponseParameter responseParameter = HttpProvider.Excute(new HttpRequestParameter
    10     {
    11         IsPost = false,
    12         Url = "http://passport.jikexueyuan.com/sso/login"
    13     });
    14     SessionCookie = responseParameter.Cookie;
    15 
    16     // 2.带上会话cookie请求验证码图片(保证是当前用户)
    17     HttpProvider.Excute(new HttpRequestParameter
    18     {
    19         Url = string.Format("http://passport.jikexueyuan.com/sso/verify?t={0}", DateTime.Now.ToString("yyyyMMddHHmmsss")),
    20         Cookie = SessionCookie,
    21         ResponseEnum = HttpResponseEnum.Stream,
    22         StreamAction = x =>
    23         {
    24             MemoryStream ms = new MemoryStream();
    25             byte[] buffer = new byte[1024];
    26             while (true)
    27             {
    28                 int sz = x.Read(buffer, 0, buffer.Length);
    29                 if (sz == 0) break;
    30                 ms.Write(buffer, 0, sz);
    31             }
    32             ms.Position = 0;
    33 
    34             BitmapImage bmp = new BitmapImage();
    35             bmp.BeginInit();
    36             bmp.StreamSource = new MemoryStream(ms.ToArray());
    37             bmp.EndInit();
    38 
    39             VerifyCode.Source = bmp;
    40 
    41             ms.Close();
    42         }
    43     });
    44 }
    获取验证码
     1 /// <summary>
     2 /// 登录方法
     3 /// </summary>
     4 /// <param name="userName">账号</param>
     5 /// <param name="userPwd">密码</param>
     6 /// <param name="verifyCode">验证码</param>
     7 void LoginDo(string userName, string userPwd, string verifyCode)
     8 {
     9     // 1.登录
    10     IDictionary<string, string> postData = new Dictionary<string, string>();
    11     postData.Add("referer", HttpUtility.UrlEncode("http://www.jikexueyuan.com/"));
    12     postData.Add("uname", userName);
    13     postData.Add("password", userPwd);
    14     postData.Add("is_ajax", "1");
    15     postData.Add("verify", verifyCode);
    16     HttpResponseParameter responseParameter = HttpProvider.Excute(new HttpRequestParameter
    17     {
    18         Url = "http://passport.jikexueyuan.com/submit/login?is_ajax=1",
    19         IsPost = true,
    20         Parameters = postData,
    21         Cookie = SessionCookie
    22     });
    23 
    24     LoginResultEntity loginResult = responseParameter.Body.DeserializeObject<LoginResultEntity>();
    25     if (loginResult.status == 1)
    26     {
    27         // 2.登录成功,保存cookie
    28         CookieStoreInstance.CurrentCookie = responseParameter.Cookie;
    29     }
    30 
    31     //MessageBox.Show(string.Format("body={0},cookie={1}", Unicode2String(responseParameter.Body),
    32     //    responseParameter.Cookie.CookieString));
    33 }
    登录代码

      流程说明:先访问极客学院任意页面(这里已首页为例,),获取到当前的用户访问的会话cookie(这里还是未登录的cookie), 然后拉取验证码,封装数据发起登录请求。把登录成功后的cooki保存在本地文件或全局变量中(本例使用),以备下载视频使用。

      (3)登录成功后,接下来就是获取视频下载地址。这里以http://www.jikexueyuan.com/course/360.html这个地址为例。访问这个地址如下图

      

      查看源代码,我们会发现一段惊奇的代码:<source src="http://cv4.jikexueyuan.com/ae892b3b4a8c63fa579af4d2c6f6bb03/201512151558/csharp/course_360/01/video/c360b_01_h264_sd_960_540.mp4" type="video/mp4" />,其中src地址就是我们所需的视频地址(必须登录才有这段代码)。因此应该先解析此页面,获取课时列表的链接。然后一个一个遍历发起Http请求(注意带cookie)获取视频地址,然后下载保存到本地。

     1 public List<LessonEntity> GetLessonEntities(string url, HttpCookieType sessionCookie)
     2 {
     3     // 请求课时列表,解析html源码,并提取课时 信息和链接
     4     HttpResponseParameter responseParameter = HttpProvider.Excute(new HttpRequestParameter()
     5     {
     6         IsPost = false,
     7         Url = url,
     8         Encoding = Encoding.UTF8,
     9         Cookie = sessionCookie
    10     });
    11 
    12     List<LessonEntity> results = new List<LessonEntity>();
    13 
    14     HtmlDocument htmlDocument = new HtmlDocument();
    15     htmlDocument.LoadHtml(responseParameter.Body);
    16     HtmlNode rootNode = htmlDocument.DocumentNode;
    17     HtmlNodeCollection lessonNodes = rootNode.SelectNodes("//div[@id="pager"]/div[3]/div[2]/div[2]/ul/li");
    18     foreach (HtmlNode lessonNode in lessonNodes)
    19     {
    20         HtmlNode aNode = lessonNode.SelectSingleNode("div[1]/h2[1]/a[1]");
    21         if (aNode != null)
    22         {
    23             results.Add(new LessonEntity
    24             {
    25                 Title = aNode.InnerText.Trim(),
    26                 Href = aNode.GetAttributeValue("href", string.Empty)
    27             });
    28         }
    29     }
    30 
    31     return results;
    32 }
    获取课时列表
    public string GetVideoUrl(string url, HttpCookieType sessionCookie)
    {
        HttpResponseParameter responseParameter = HttpProvider.Excute(new HttpRequestParameter
        {
            Url = url,
            Cookie = sessionCookie
        });
        // 正则提前视频文件 地址
        string result = Regex.Match(responseParameter.Body, "<source.*src="(.+?").*/>").Groups[1].Value.Replace(""", string.Empty);
        sessionCookie = responseParameter.Cookie;
        return result;
    }
    获取视频地址
    public void DownloadVideo(string filePath, string url, HttpCookieType sessionCookie, Action action = null)
    {
        string folder = Path.GetDirectoryName(filePath);
        if (!string.IsNullOrEmpty(folder) && !Directory.Exists(folder))
        {
            // 如果目录文件夹不存在, 则创建
            Directory.CreateDirectory(folder);
        }
        if (action != null)
        {
            action();
        }
    
        HttpProvider.Excute(new HttpRequestParameter
        {
            Url = url,
            ResponseEnum = HttpResponseEnum.Stream,
            Cookie = sessionCookie,
            StreamAction = x =>
            {
                NetExtensions.WriteFile(filePath, x);
            }
        });
    
        //WebClient webClient = new WebClient();
        //webClient.DownloadFile(new Uri(url, UriKind.RelativeOrAbsolute), filePath);
    }
    下载视频
     1 public void DownloadCode(string filePath, string courseId, HttpCookieType sessionCookie)
     2 {
     3     if (File.Exists(filePath)) return;
     4 
     5     HttpResponseParameter responseParameter = HttpProvider.Excute(new HttpRequestParameter
     6     {
     7         Url = string.Format("http://www.jikexueyuan.com/course/downloadRes?course_id={0}", courseId),
     8         Cookie = sessionCookie
     9     });
    10     CodeDownloadResultEntity result = responseParameter.Body.DeserializeObject<CodeDownloadResultEntity>();
    11     if (result.code == 200)
    12     {
    13         string folder = Path.GetDirectoryName(filePath);
    14         if (!string.IsNullOrEmpty(folder) && !Directory.Exists(folder))
    15         {
    16             // 如果目录文件夹不存在, 则创建
    17             Directory.CreateDirectory(folder);
    18         }
    19 
    20         WebClient webClient = new WebClient();
    21         webClient.DownloadFile(new Uri(result.data.url, UriKind.RelativeOrAbsolute), filePath);
    22     }
    23 }
    下载课件和源码

      (4)、至此视频下载功能已完成。那么我们要批量下载极客学院【职业路径图课程视频】就相当简单了(http://ke.jikexueyuan.com/zhiye/),一步一步解析页面,获取到视频播放页地址,下载视频(解析页面主要用到正则表达式HtmlAgilityPack框架)。

      (5)如此,极客学院职业路径图课程就可以尽收囊中。

    四、源码下载

        极客学院视频下载程序

      “苟富贵勿相忘”,如果这篇文章是你认为好的,无论你是一直潜水,请点个赞好吗?

  • 相关阅读:
    【MySQL】Mysql模糊查询like提速优化
    mysql实现row_number()和row_number() over(partition by)
    mysql limit 分页优化
    js正则验证方法大全
    如何获取select下拉框中option选中的文本值
    js控制input框只能输入数字和一位小数点和小数点后面两位小数
    js页面 :函数名 is not defined
    算法名称 Alias Method
    解决mybatis报错Result Maps collection does not contain value for java.lang.Integer
    nginx的rewrite规则
  • 原文地址:https://www.cnblogs.com/GodX/p/5047769.html
Copyright © 2020-2023  润新知