Y's note

Web技術・プロダクトマネジメント・そして経営について

本ブログの更新を停止しており、今後は下記Noteに記載していきます。
https://note.com/yutakikuchi/

WebCrawler in Scala

Crawler in Scala

検索Crawlerを作る - Web就活日記 はてなブックマーク - 検索Crawlerを作る - Web就活日記
以前はnutchを使ったcrawlerを試してみましたが、今回はcrawler自体をscalaで書いているものをまとめようと思います。インターネットで紹介されているものの中には全然使えないものもあったりするので、選択には気をつけてください。個人的にはまとめた結果からJoupHtmlUnitDriverが記述や設定が簡単で手軽に実行できるという点でお薦めしたいツールになっています。

nomad

denigma/nomad はてなブックマーク - denigma/nomad
JDK/JRE7、MongoDB、Debianを必要とします。これによって私はテストしませんでしたが。sourceの更新も2年前で止まってしまっていますね。。application.conf、filters.groovy、seeds.txtの3つのファイルを記述するだけで簡単に動かせて、結果をMongo上で確認できるようなのでDebianUserは試してみると良いかもしれません。

simplewebcrawler

Srirangan/simplewebcrawler はてなブックマーク - Srirangan/simplewebcrawler
ScalaとGridGainを必要とします。GridGainでjobを分割することで並列分散処理をやっているみたい。GridGainを使うというニッチ派は聞いた事が無いので、何かしら問題が発生した時に大変そうです。

fureteur

gip/fureteur はてなブックマーク - gip/fureteur
おそらく紹介する中で一番作りこまれている印象を受けました。RabbitMQを利用した分散Crawlingを実現、akkaのactorでmoduleを実装、スケジューリングを管理してくれる、sbtで用意されているので簡単に利用できる等の特徴があります。本気でCrawlerを作りたい人向けですかね。

crawler

bplawler/crawler はてなブックマーク - bplawler/crawler
指定したURLから再帰的にリンクを見つけてCrawlしてくれます。ただしドキュメントがほとんど無く初心者には設定がよくわからない、READMEの記述が誤っている、複雑なTagのパースがうまくできない(?)、様々なサイトのリンクを取得しようとするとExceptionがたくさん出て処理が進まないなど使用するのは困難と言えます。評価出来る内容としてはsbtによるbuild管理と、少ないコード記述でcrawlerができてしまうこと。以下は簡単に導入の内容を記載しておきます。

$ git clone  https://github.com/bplawler/crawler.git
$ cd crawler
$ cp build.sbt build.sbt.bak
$ vi build.sbt
$ diff -u build.sbt build.sbt.bak
--- build.sbt	2014-12-30 09:17:54.895512815 +0900
+++ build.sbt.bak	2014-12-30 09:48:18.683566361 +0900
@@ -8,8 +8,6 @@

 scalacOptions := Seq("-deprecation", "-unchecked", "-feature")

-mainClass in (Compile, run):= Some("crawl")
-
 libraryDependencies ++= Seq (
     "net.sourceforge.htmlunit" % "htmlunit" % "2.15"
   , "org.specs2" %% "specs2" % "1.14" % "test"

$ vi src/main/scala/test.scala  //下のファイルを記述
$ sbt
> run
[info] Compiling 1 Scala source to /home/yuta/work/git/crawler/target/scala-2.10/classes...
[info] Running crawl
import crawler._
import java.io._

class TestCrawler extends Crawler {
  def crawl = {
     navigateTo("http://search.yahoo.co.jp/search?p=scala") {
     }
     onCurrentPage {
       try {
         forAll(div having xPath("//body/div")) {
           println(from(anchor having xPath("a")).getTextContent)
         }
       } catch {
         case e : NoSuchElementException  => println("NO TAG")
         case e : org.apache.http.client.ClientProtocolException => println("PROTOCOL ERROR")
       }
     }
  }
}

object crawl {
 def main(args: Array[String]) {
   val c = new TestCrawler
   c.crawl
 }
}
JSoup

jsoup Java HTML Parser, with best of DOM, CSS, and jquery はてなブックマーク - jsoup Java HTML Parser, with best of DOM, CSS, and jquery
CrawlerというよりはHTML Parserの紹介になってしまいますが、JavaのHTML ParserでJsoupという強力なLibraryがあります。これをScalaから実行します。XPathやDomでの操作が簡単にできるので気軽に試せます。

$ git clone https://github.com/yutakikuchi/scala.gi
$ cd scala/scala-jsoup
$ cat build.sbt
name := "scala-jsoup"

scalaVersion := "2.10.2"

scalaBinaryVersion := "2.10"

mainClass in (Compile, run):= Some("crawl")

libraryDependencies += "org.jsoup" % "jsoup" % "1.8.1"

$ vi src/main/scala/crawl.scala //下のscalaを記述

$ sbt
> run
import org.jsoup._
import collection.JavaConverters._

object crawl {
  def main(args: Array[String]) {
    try {
      val urlstr = "http://search.yahoo.co.jp/search?p=scala"
      val doc = Jsoup.connect(urlstr).get
      val tag = doc.select("#res > #web > ol > li").asScala.head
      println(tag)
    } catch {
       case e : NoSuchElementException  => println("NO TAG")
    }
  }
}
HtmlUnitDriver

HtmlUnitDriver はてなブックマーク - HtmlUnitDriver
HtmlUnitDriverはJavaで実装されています。Seleniumなどの自動テストツールにも組み込まれているWebDriverを使って自動的にリンクを横断してCrawlすることも可能でとても便利。また設定や記述も簡単で、Jsoupと同様にXPathやDom操作を得意としています。

$ git clone https://github.com/yutakikuchi/scala.gi
$ cd scala/scala-webdriver
$ cat build.sbt
name := "scala-webdriver"

scalaVersion := "2.10.2"

scalaBinaryVersion := "2.10"

mainClass in (Compile, run):= Some("crawl")

libraryDependencies += "org.seleniumhq.webdriver" % "webdriver-htmlunit" % "0.9.7376"

$ vi src/main/scala/crawl.scala //下のscalaを記述

$ sbt
> run
import scala.collection.JavaConversions._
import org.openqa.selenium.htmlunit.HtmlUnitDriver
import org.openqa.selenium._

object crawl {
  def main(args: Array[String]) {
    try {
      val urlstr = "http://search.yahoo.co.jp/search?p=scala"
      val driver = new HtmlUnitDriver()
      driver.get(urlstr)
      var res = driver.findElementsByXPath("//li/a")
      for(r <- res) {
        println(r)
      }
    } catch {
       case e : NoSuchElementException  => println("NO TAG")
    }
  }
}