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

编程入门 行业动态 更新时间:2024-10-09 07:22:07

用Scala打造<a href=https://www.elefans.com/category/jswz/34/1752679.html style=精悍爬虫(二)视频篇"/>

用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 + "/" + path2if (!(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 = "/?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的很多特性(如类型推断,隐式转换,众多语法糖等等),让它变成一门极高“信噪比”的语言。显然,更少的代码,会让维护都变得更容易。但同时,灵活掌握这些特性也有一定难度,我想这也许是它始终无法普及的原因吧。

更多推荐

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

本文发布于:2024-02-07 01:26:52,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1752652.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:精悍   爬虫   视频   Scala

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!