HTMLスクレイピング in Scala その1
スクレイピングして遊ぶために、文字コードを判別してHTMLソースを取得するコードをScalaで書いてみました。
実装
HtmlScraping.scala
import scala.io.Source import scala.util.matching.Regex object Html{ def getSource(url: String): List[String] = { val src = Source.fromURL(url, "ISO-8859-1").getLines.toList var charset: String = null val regex = new Regex("""charset[ ]*=[ ]*[0-9a-z|\-|_]+""") for(line <- src){ val lower = line.toLowerCase if(lower.contains("content") && lower.contains("charset")){ charset = regex.findFirstIn(lower).get charset = charset.split("=")(1).trim } } return if(charset == null) src else Source.fromURL(url, charset).getLines.toList } def main(args: Array[String]) = { val src = getSource(args(0)) println(src) } }
REPLで実行してみる
scala> :load .\HtmlScraping.scala
Loading .\HtmlScraping.scala... import scala.io.Source import scala.util.matching.Regex defined module Html
試しに charset=utf-8 のYahooさんのページ
scala> Html.getSource("http://www.yahoo.co.jp")
res0: List[String] = List(<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitio nal//EN" "http://www.w3.org/TR/html4/loose.dtd">, <html>, <head>, <meta http-equ iv="content-type" content="text/html; charset=utf-8">, <meta http-equiv="content -style-type" content="text/css">, <meta http-equiv="content-script-type" content ="text/javascript">, <meta name="description" content="日本最大級のポータルサイ ト。検索、オークション、ニュース、メール、コミュニティ、ショッピング、など80以上 のサービスを展開。あなたの生活をより豊かにする「ライフ・エンジン」を目指していき ます。">, <title>Yahoo! JAPAN</title>, <base href="http://www.yahoo.co.jp/_ylh=X 3oDMTB2OHNyYWxqBF9TAzIwNzkxODE5OTkEdGlkAzEzBHRtcGwDdGFibGU-/">, <style type="tex t/css">, <!--, body{word-break:break-all;font:12px/1.22 "Osaka", "MS Pゴシッ ク", Arial, sans-serif;*font-size:small;*font:x-small;}, table{font-size:inherit ;font:100%;}, pre,co...
取得できました。
試した限りではeuc-jp, shift_jis のページも無事取得出来ました。
Source.fromURL
文字コードが固定されているのであれば、一行で取得したソースを表示するコードが書けます。
scala> Source.fromURL("http://hogehoge.jp/", "utf-8").foreach(c => print(c))
ただし、実際には様々な文字コードのページが氾濫しているのでクローラなどを開発する際には文字コード判別は無視できないでしょう。
本格的に文字コードを判別するにはもっと複雑な処理が必要なのですが、今回は最初に"ISO-8859-1"で読み込みHTMLに記述されたContent-typeのcharsetを取得し、そのcharsetを使って再度 Source.fromURL を実行してソースを取得するという実装にしています。もっと良い方法があれば教えてください!
生文字リテラル
正規表現のパターンの記述には生文字リテラルを使用してみました。
PHPで言うヒアドキュメントのようなものです。
生文字リテラルには以下の特徴があります。
・エスケープ文字を持たない
・複数行の文字列をコードの中で記述することが出来る。
これでJavaなどで正規表現を使うときによくやっていた 二重の¥マーク だらけの煩雑な記述を回避できます。
次回は実際にHTMLをスクレイピングするコードを書こうと思います。