`
duanhengbin
  • 浏览: 383414 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

用Scala打造精悍爬虫(二)视频篇

 
阅读更多

【项目简述】

抓取某学院视频网站的系列课程,相比于上一篇,这一次多了不少实用性。

 

【前提】

必须要有该网站的VIP账户,主要是Cookies要使用,否则无法获取一部分受限视频。当然有不少免费获取VIP账户的方法可以自行搜索。

 

【视频网站的特点】

1)这类网站一般都有不同程度的反扒措施,某学院采用的是动态缓存,即是有权限的会员打开网页才能获取该视频的Url,这个Url有一定时效性,不适合大量抓取Url后再下载(等全抓完前面的已失效了)。但是边抓取Url边下载是没有问题的,这是较容易爬取的一类。网页的分析和以前并无分别,用F12搞定。

2)由于目标文件数量多,文件的组织比较重要,url中的文件名并不适合于文件保存(人类无法理解。。。)。这里采用最符合阅读习惯的方式对于不同层级建目录,文件名直接采用页面标题命名。另外网页上有些层级的内容未带序号,为避免下载以后排序混乱的问题,需要在前面追加序号。

3)由于目录和文件名来自网页,就会有相对于操作系统的非法字符问题,比如windows下 \/:*?"<>| 这些字符是不能出现在目录文件中的。另外还有不少其他非法文字。

4)视频文件爬取比较耗时,不要期望一次性成功,所以必须要有重复检测,即遇到已爬取的文件直接跳过。

 

先上核心代码

for( i <- 1 to 5;
     e1 <- fCrawl(url.format(i)).select("div.lesson-card");
       path1 = e1.select("h2").text.stripIllegalChar;
     (e2,j)  <- fCrawl(e1.select("div.text a").attr("href")).select("div.lesson-item").zipWithIndex;
       path2 = j + 1 + "_" +e2.select("dt.title").text.stripIllegalChar;
     e3 <- fCrawl(e2.select("a").attr("href")).select("dl.lessonvideo-list a")){
  val file = e3.text.stripIllegalChar+".mp4"
  val path = BASE_PATH + "/" + path1 + "/" + path2
  if (!(new java.io.File(path+"/"+file)).exists){
    fDownload(path, file, fCrawl(e3.attr("href")).select("source").attr("src"))
    println(s"$path\t$file\t下载成功!")
  }else{
    println(s"$path\t$file\t已下载!")
  }
}

 

是的,你没有看错,得益于Scala强大的表现力,核心代码就只有这10几行。当然还没有把一些辅助型代码算在内。

 

说明:

  • 首先是Scala的for语句实际上是一个可用于多层次迭代的语法糖,上面的语句实际上产生了四层迭代。第一层 1 to 5 是对分页的迭代,后面每一层进入一次页面抓取,最后循环体内的fcrawl就可以抓取到视频Url了。类似如下结构:

(1 to 5)

  .foreach(i => fCrawl(url.format(i)).select("div.lesson-card") )

    .foreach( e1 => fCrawl(e1.select("div.text a").attr("href")).select("div.lesson-item").zipWithIndex)

      .foreach( (e2,j) => fCrawl(e2.select("a").attr("href")).select("dl.lessonvideo-list a")))))

 

  • e2级中,zipWithIndex这个方法是用来给迭代对象添加序号的,由于Scala的序号从0开始,所以使用的时候还需要加1。
  • 熟悉Scala的朋友一定会问,stripIllegalChar是什么鬼,居然用在了String类型上。这个其实是Scala的黑科技之一隐式类,很多时候,它能让代码更加优雅。

真相在这里

implicit class StringImprovement(val s : String){
    // 删除文件名中的非法字符
  def stripIllegalChar = s.replaceAll("???", "").replaceAll("\\\\|/|:|\\*|\\?|<|>|\\||\"", "")
}

 

现在String类型的对象就可以使用stripIllegalChar方法去删除那些非法字符了。???是特指一些无法显示的非法字符,这个只能遇到的时候,现去添加,由于该程序有重复文件判断,所以每次异常修改后,直接再次执行就好了。

 

fCrawl,fDownload这两个方法就是简单递归自身保证Url抓取和文件下载的成功。

def fCrawl(url: String): Document = 
  Try(Jsoup.connect(url).timeout(0).cookies(cookies).get()) match {
    case Failure(e) => println(e.getMessage); sleep(10000); fCrawl(url)
    case Success(d) => d
  }

def fDownload(path: String, file: String, url: String): Unit =
  Try(JavaHelper.download(path, file, url)) match {
    case Failure(e) => println(e.getMessage); sleep(10000); JavaHelper.download(path, file, url)
    case Success(_) =>
  }

 

异常的时候三步:异常信息打印,暂停10秒,再次执行。

 

 

最后是JavaHelper.download方法,由于jsoup下载文件的能力较差,自己写了一个java方法如下(实际运行下来发现还蛮健壮,极少出错):

public static void download(String path, String fileName, String fileUrl) throws IOException {
    File pathFile = new File(path); 
    if (!pathFile.exists()) {
        pathFile.mkdirs();
    }
      
    URL url = new URL(fileUrl);
    InputStream inStream = url.openConnection().getInputStream();
    FileOutputStream fs = new FileOutputStream(path + "/" + fileName);

    byte[] buffer = new byte[1204];
    int byteread = 0;
    while ((byteread = inStream.read(buffer)) != -1) {
        fs.write(buffer, 0, byteread);
    }
    fs.close();
}

 

其他代码

// Url源
val url = "http://ke.jikexueyuan.com/xilie/?page=%d"
// 存储路径
val BASE_PATH = "G:/video/Series"

def sleep(i: Long) = Thread.sleep(i)
// 这里设置你的vip账户的cookies信息,用F12你应该懂的
val cookies = new java.util.HashMap[String,String]
cookies.put("uname", "???") 
cookies.put("authcode", "???") 

 

经过累计时间差不多1天的半值守运行,成功下载了带有良好目录结构的3000+视频文件。

 

小结: Scala的很多特性(如类型推断,隐式转换,众多语法糖等等),让它变成一门极高“信噪比”的语言。显然,更少的代码,会让维护都变得更容易。但同时,灵活掌握这些特性也有一定难度,我想这也许是它始终无法普及的原因吧。

0
5
分享到:
评论

相关推荐

    scala实战高清讲解

    scala编程进阶过程中不可或缺的书籍之一,详细介绍了scala语言的各种中高级语法,对于初学和高级开发人员有很大帮助

    Scala.pdf中文高清第二版

    Scala.pdf中文高清第二版,初学者学习Scala的必备参考资料

    scala学习视频&pdf;讲义

    scala学习视频资料以及讲义,从基础的环境配置开始讲起,以及后面具体案例开发.适合新手学习,还有具体讲义对照复习查看。

    Scala语言视频百度网盘

    第01阶段 :Scala 入门 第02阶段:Scala 的函数式编程 第03阶段:Scala 的面向对象编程 第04阶段:Scala的高级基础一 第05阶段:Scala的高级基础二

    Scala函数式编程

    1 scala用起来比java更灵活 2 强大的collection,可以更加方便的处理collection类的数据 3 不同于java的并行处理方法,有点像c的逻辑思路 4 开发成本比java小,但是语言学习成本比java高很多 正在阅读这本书的...

    最新整理的大数据scala和spark视频教程

    最新整理的大数据scala和spark完整视频教程包括资料,老师讲的很好。

    快学scala第二版中英文.zip

    你可以使用Scala编写出更加精简的程序,同时充分利用并发的威力。由于Scala默认运行于JVM之上,因此它可以访问任何Java类库并且与Java框架进行互操作。通过ScalaJS项目,Scala还可以被编译成JavaScript代码,让我们...

    streamerz, 在 Scala 中,Akka流和视频处理.zip

    streamerz, 在 Scala 中,Akka流和视频处理 Streamerz在Akka流和 Scala ( 用一些 Kafka ) 中的视频处理示例的。人们一直认为通过meme工程学习主题是最好的方法。 这套库使你可以轻松地获得所有的乐趣。示例使用Ascii...

    scala sdk scala-2.12.3

    scala-2.12.3 scala-2.12.3 scala-2.12.3 scala-2.12.3

    快学scala2.0

    快学scala的最新版本,独家一份,学习spark2.0的必备入门书籍,快来下载,绝对高清

    scala学习视频(基础)&讲义

    scala学习视频资料以及讲义,从基础的环境配置开始讲起,以及后面具体案例开发.适合新手学习,还有具体讲义对照复习查看。

    SCALA编程思想 原书第2版 PDF 下载

    本书介绍Scala的基础特性,采用短小精悍的“原子”解构Scala语言的元素和方法。一个“原子”即为一个小型知识点,通过代码示例引导读者逐步领悟Scala的要义,结合练习鼓励读者在实践中读懂并写出地道的Scala代码。...

    头歌Scala中集合的使用

    Scala中集合的使用 大学生 1. List 列表的使用 2. Set 集合的使用 3.Map 映射的使用 4. 元组的使用

    Scala语法简明教程

    Scala语法简明教程.pdf

    scala五本经典资料集合

    但是现在scala的相关学习资料不多,因此,本人总结了几篇写的较好的scala学习资料,包含&lt;ScalaQuery_Commerzbank_2011&gt;&lt;twitter-scala&gt;&lt;TR611&gt;&lt;scala-style-guide&gt;。因此,无论是初学者,还是想要深入研究scala的...

    尚硅谷大数据之韩顺平Scala全套视频

    看过的scala教程中讲的最好的,为老师点赞。最新尚硅谷大数据之韩顺平Scala视频教程

    Scala for the Impatient 第二版

    快学Scala第二版英文书,只要3分,大家一起学习

    scala-sbt-scala编译工具

    scala 编译工具 sbt 安装包。 Little or no configuration required for simple projects Scala-based build definition that can use the full flexibility of Scala code Accurate incremental recompilation ...

    Scala编程实战.zip

    此文档是讲解实战Scala,...本书面向实际的使用场景,提供了大量的Scala实例,同时,也给出底层的原理和相关的参考。对于Scala新手来说这是一本不错的入门书,对于老手来说也是一本夯实基础,检视自己所学知识的好书。

Global site tag (gtag.js) - Google Analytics