読者です 読者をやめる 読者になる 読者になる

HTMLReaderというフレームワークがすごい

HTMLをクライアント側でちょっとパースする要件にてiOSで使えるHTMLパーサを調べると、いくつかあるのですが、HTMLReaderというのがたまたま目につきました。

// Bridge-Headerにて、HTMLDocument.hとHTMLSelector.hをインクルードしてる
import UIKit
import Alamofire

class ViewController: UIViewController {
    @IBOutlet weak var textView: UITextView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let req = request(.GET, "http://number.bunshun.jp/articles/-/821939")
        req.responseString { (_, _, data, _) in
            var text = ""
            let html = HTMLDocument(string: data)
            if let ogTags = html.nodesMatchingSelector("meta[property^=\"og:\"]") {
                for tag in ogTags {
                    let property = tag.attributes?["property"] as? String
                    let content = tag.attributes?["content"] as? String
                    if property != nil && content != nil {
                        text = text + "meta[" + property! + "] => " + content! + "\n"
                    }
                }
            }
            dispatch_async(dispatch_get_main_queue()) { () in
                self.textView.text = text
            }
        }
    }
}

シングルViewの雛形に、UITextViewを一個貼っただけの画面を用意して、起動時に外部URLを叩いてます。今回はNumber WEBでACミラン本田の活躍記事です。実行すると以下のようにページをスクレイピングして情報を表示しました。

f:id:masataka_k:20141030040608p:plain

このHTMLReaderのポイントはまるでjQueryのようにCSS Selectorでタグ抽出できるところです。始めに文字列からHTMLDocumentを生成し、 HTMLNode#nodesMatchingSelector(String) ほか随所にてCSS Selectorを用いて検索をかけられます。例では「meta[property^="og:"]」というSelector式でOpen Graph Protocol (OGP)関連の情報だけを取り出しています。ちなみにOGPはFacebookでリンクシェアしたときに埋め込んでくれるWEBページのタイトル、写真、概要などをスクレイピングするための標準です。上下でHTMLReaderとOGPのサイトリンクを埋め込むのにはてなブログが作ってくれているコラムのようなものをページ側の意図を汲んで表示するための標準。

更にこのライブラリは、HTMLSerialization.hを追加インクルードさせることでDOM操作した結果のHTMLを文字列出力することができます。アプリケーションでHTMLテンプレート機能も容易に作れる。外からHTML取ってきてaタグやimgタグをローカル化させたりも手数少なく可能かな。

しかし、直後からXCode6.1が大乱調。SourceKitがクラッシュしたっていうのです。以下のURLと同じ状況なのですが回避方法が不明で、調べてもたくさんの人が困ってて、かつ誰もはっきりとした解決をしていないという状況でした。まあ明らかにXCodeのバグとしか思えないし、HTMLReaderが悪いわけじゃないと思いますけど状況的にSwiftと相性悪いのかも。せっかくいいフレームワークなのに環境クラッシュするとどうにもならないので、XCodeがアップデートされるまでしばらくは別の方法でしのいでおきます。

ios - SourceKitService Terminated - Stack Overflow