Scalaでスクレイピング
ライブラリ
やってみた
build.sbt
name := "scalascraping1" version := "0.0.1" libraryDependencies += "org.jsoup" % "jsoup" % "1.7.3"
main.scala
import org.jsoup._ import collection.JavaConverters._ object Main { def main(args: Array[String]): Unit = { val doc = Jsoup.connect("http://b.hatena.ne.jp/hotentry").get // asScalaで、JavaのArrayをScalaのcollectionに変換しないと、forで回せない for (t <- doc.select("a.entry-link").asScala) { println(t.text()) println(t.attr("href")) } } }
実行
$ sbt run ネット民戦慄! 表現の自由を脅かす”ゾーニング破り”とは? - トゥギャッチ http://togech.jp/2015/12/14/30710 ビジネス問題解決フレームワーク20選|今日から使えて最速で成長できる http://career-theory.net/business-flamework-3002 App Storeの弊社デベロッパーアカウント停止に至った 経緯につきまして|株式会... http://nagisa-inc.jp/news_release/20151214/1631 科学的調理法で作ったお手軽一人鍋がやばかった http://anond.hatelabo.jp/20151214095821 職員が個人情報68万人分流出させる 大阪・堺市 NHKニュース http://www3.nhk.or.jp/news/html/20151214/k10010340801000.html 所得低いほど高い喫煙率、歯少なく肥満者多い : 社会 : 読売新聞(YOMIURI ONL... http://www.yomiuri.co.jp/national/20151214-OYT1T50013.html ...
PHP7のThrowableを利用したキャッチ
PHP7からErrorクラスが新設されて、文法エラーのような例外も捕捉できるようになった。
Errorクラスも既存のExceptionクラスも、Throwableインターフェースを実装しているので、完全なキャッチは以下のようになる、と思う。
<?php function add(int $a, int $b): int { return $a + $b; } echo add(123, 234), "\n"; // => 357 //try { // echo add('hoge', 'fuga'), "\n"; //} //catch (Exception $e) { // echo "Exception: ", $e->getMessage(), "\n"; //} // // 拾えずに「PHP Fatal error: Uncaught TypeError: Argument 1 passed to add() must be of the type integer, string given〜」が発生する try { echo add('hoge', 'fuga'), "\n"; } catch (\Exception $e) { echo "Exception: ", $e->getMessage(), "\n"; } catch (\Throwable $e) { echo "Throwable: ", $e->getMessage(), "\n"; } // 「Throwable: Argument 1 passed to add() must be of the type integer, string given〜」で拾える echo "finish\n"; // この処理も継続して動く
PHPでArrayOptionクラスを作った
PHPのArrayは存在しないキーにアクセスすると、Noticeのエラーが発生する。
なので、isset()やら、array_key_exists()をしてから取りに行くのだけど、どうにも面倒だった。
最近覚えたScalaのgetOrElse()みたいなことができればいいなと思って、作ってみた。
json_decode()した結果を入れると、捗る。
こんな感じで使う
<?php require "./ArrayOption.php"; $j = json_decode('{"hoge":{"fuga":{"piyo":123}}}', $assoc = true); $arr = new ArrayOption($j); echo $arr->hoge->fuga->piyo->get(), "\n"; // 123 echo $arr->hoge->fuga->piyo->getOrElse(234), "\n"; // 123 echo $arr->hoge->fuga->foo->getOrElse(999), "\n"; // 999 var_dump($arr->hoge->get()); //array(1) { // 'fuga' => // array(1) { // 'piyo' => // int(123) // } //} $arr->abcde->get(); //PHP Fatal error: Uncaught exception 'ArrayOptionNoSuchElementException'
いいところ
get()とgetOrElse()で、キーの存在確認とクオートを打つ手間とプロパティ呼び出しの簡潔さがいい感じである。
悪いところ
毎回オブジェクト作ってるので、それなりに遅いです。
<?php $arr = ['hoge' => ['fuga' => ['piyo' => ['foo' => ['bar' => 123]]]]]; $count = 100000; for ($i = 1; $i <= $count; $i++) { $k = $arr['hoge']['fuga']['piyo']['foo']['bar']; } //=> 0.030924 sec for ($i = 1; $i <= $count; $i++) { $arroption = new ArrayOption($arr); $k = $arroption->hoge->fuga->piyo->foo->bar->get(); } //=> 2.622408
実に84倍の差が出てしまいました。