scrala 初探(一)

来源:互联网 发布:备孕前准备 知乎 编辑:程序博客网 时间:2024/06/07 02:54
import com.gaocegege.scrala.core.spider.impl.DefaultSpiderimport com.gaocegege.scrala.core.common.response.impl.HttpResponseimport org.jsoup.helper.StringUtilimport  scala.collection.mutable.Setimport  scala.collection.mutable.Mapclass SpiderDouYu extends DefaultSpider {  var main_url_format = "https://www.douyu.com/directory/game/%s?page=%d&isAjax=1"  var sub_url_format = "https://www.douyu.com/directory/subCate/%s/%s?page=%d&isAjax=1"  var item_dict = Map[String, Map[String, String]]()  var target_status_dict = Map[String, Map[String, Map[String, String]]]()  var urlsSet = Set[String]()  abstract class MetaCallback  case class category(url: String, game_name: String)extends Function1[HttpResponse, Unit]  {    override def apply(response: HttpResponse) = {      if (response.getContentParser().select("div[class=nonText]").isEmpty){        val tag_list = (response.getContentParser()).select("div[class=tag_list] > ul").select("a")        if(!tag_list.isEmpty)          {            target_status_dict += (game_name -> Map[String, Map[String, String]]())            for(i <-  0 to tag_list.size - 1)              {                var url_split_array : Array[String] = tag_list.get(i).attr("data-href").split("/")                var label = tag_list.get(i).text()                var url = ""                if(!"全部".equals(label))                  url = sub_url_format.format(url_split_array(url_split_array.size - 2), url_split_array(url_split_array.size - 1), 1)                else                  url = main_url_format.format(url_split_array(url_split_array.size - 1), 1)                var map = Map[String, String]("url" -> url, "status" -> "false")                target_status_dict(game_name) += (label -> map)                if(!"全部".equals(label))                  request(url, video(url, game_name, label, "2", "true", url_split_array(url_split_array.size - 2) + "/" + url_split_array(url_split_array.size - 1)))              }          }        else {         var url_split_array: Array[String] = this.url.split("/")          var url = main_url_format.format(url_split_array(url_split_array.size - 1), 1)          target_status_dict += (game_name -> Map[String, Map[String, String]]())          var map = Map[String, String]("url" -> url, "status" -> "false")          target_status_dict(game_name) += ("" -> map)          request(url, video(url, game_name, "", "2", "false", url_split_array(url_split_array.size - 1)))        }      }    }  }  case class video(url: String, game_name: String, category: String, page: String, haveCategory: String, format_args: String)extends Function1[HttpResponse, Unit]  {    override def apply(response: HttpResponse): Unit =    {      var will_return = false      var temp_urlsSet = urlsSet.clone()      temp_urlsSet += response.getContentParser().select("li > a").attr("href")      if(temp_urlsSet == urlsSet)        will_return = true      if (!will_return)        {          var page_url: String = this.url          var video_Elements = response.getContentParser().select("li").select("a")          for(i <-  0 to video_Elements.size - 1)            {              var video_Element = video_Elements.get(i)              var VideoUrl = StringUtil.resolve(page_url, video_Element.attr("href"))              if(!urlsSet.contains(video_Element.attr("href")))                {                  urlsSet += video_Element.attr("href")                  var item_hash = Map[String, String]()                  item_hash += ("url" -> VideoUrl)                  item_hash.+= ("img" -> video_Element.select("span>img").attr("data-original"))                  item_hash += ("video_name" -> video_Element.select("h3[class='ellipsis']").text())                  item_hash.+= ("anchor" -> video_Element.select("span[class=dy-name ellipsis fl]").text())                  item_hash += ("origin_class" -> category)                  item_hash += ("room_id" -> video_Element.attr("data-rid"))                  var popularity_text = video_Element.select("span[class=dy-num fr]").text()                  var popularity: Int = 0                  if (popularity_text.contains("万"))                  {                    popularity_text = popularity_text.replace("万", "");                    popularity = (popularity_text.toDouble * 10000).toInt;                  }                  else                  {                    try{                      popularity = popularity_text.toInt                    }catch{                      case e: Exception => popularity = 0                    }                  }                  item_hash.+= ("popularity" -> popularity.toString);                  item_dict += (item_hash("url") -> item_hash.clone())                  request(item_hash("url"), individual(item_hash("url")))                }            }          var format_args: Array[String] = this.format_args.split("/")          var page_num = this.page.toInt          page_num += 1          var url: String =  ""          if(this.url.contains("subCate"))            url = sub_url_format.format(format_args(0), format_args(1), page_num)          else            url = main_url_format.format(format_args(0), page_num)          request(url, video(url, game_name, category, page_num.toString, haveCategory, this.format_args))        }      else {        var game = target_status_dict(game_name)        game(category) += ("status" -> "true")        var all_end: Boolean = true        var GameNameDict = target_status_dict(game_name)        for(h: Map[String, String] <- GameNameDict.values) {          if (h("status").equals("false")) {            all_end = false          }        }        if(all_end)        {          for(key: String <- GameNameDict.keySet)          GameNameDict(key) -> ("status" -> "false")          if(GameNameDict.keySet.contains("全部"))          {            var MainUrl: String = GameNameDict.get("全部").get("url")            var url_split_array: Array[String]  = MainUrl.split("/")            request(MainUrl, video(url, game_name, "", "2", "false", url_split_array(url_split_array.size - 1)))          }        }      }      }    }  case class individual(url: String)extends Function1[HttpResponse, Unit]  {    override def apply(response: HttpResponse): Unit = {      var item_hash = item_dict(url)      var avatar = response.getContentParser().select("div[class=anchor-pic fl]>img").attr("src")      if (avatar.length() == 0)        avatar = response.getContentParser().select("div[class=h_tx fl]>img").attr("src")      item_hash += ("avatar" -> avatar);      println("item_hash : " + item_hash)    }  }  def startUrl = List[String]("https://www.douyu.com/directory")  def parse(response: HttpResponse): Unit = {    val links = (response.getContentParser()).select("ul[id=live-list-contentbox]>li[class=unit ]")    for(i <-  0 to links.size - 1){      val url = StringUtil.resolve(startUrl(0), links.get(i).select("a").attr("href"))      val game_name = links.get(i).select("a").select("p").text()      request(url, category(url, game_name))    }  }}object Main {  def main(args: Array[String]) {    val test = new SpiderDouYu()    test.workerCount = 10    test begin  }}

有了scala的小基础就可以练一练手

使用scala爬虫框架scrala 该框架官网见:http://gaocegege.com/scrala/

基本没有文档,不过由于其基本是使用与scrapy类似的结构,故可以轻松上手。

下面的代码是将webcollector初探(三)的java代码用scala写出来并实践的结果。

这里对一些过程给出说明。

scrala的安装方法使用了intellij idea sbt 插件进行jar包依赖下载,相应build.sbt设置见scrala官网源码。

(一定要注意scala的版本要与源码一致)

首先声明,由于源码中的

DefaultSpider 使用的是默认不进行判重的设定(见源码),故省去了代码逻辑中禁止判重的部分。
由于request回掉函数被指定了固定类型且框架中没有提供类似scrapy meta的传递信息方法(webcollector提供了),

故利用scala的特殊特性,对abstract类MetaCallback extends Function1 使其具备callback函数的调用接口类型,

并将类的初始化作为完成meta传递信息的方法,最终分不同的case初始化回掉类。

将scala的语言特性实现逻辑相结合。

剩下的基本就是语言翻译了(java to scala)


从运行结果来看,速度较webcollector慢,这里采用了默认的4线程,但是内存占得相当高。
个人对Akka不太了解 不过 了解可以从现在开始 见 Akka 初探(一)
0 0
原创粉丝点击