Help us understand the problem. What is going on with this article?

Swift製HTMLパーサ「Kanna」

@shu223 さんのpost ”手軽に使えるSwift製HTMLパーサ「Ji」” に名前が出ていたので
Kannaも紹介記事を書いてみます。

Github: Kanna(鉋)

追記:2015/9/2
1. バージョンアップしました(0.1.3 => 0.1.4)
   手元のバージョンで説明を書いてしまっていたため一部コードが動かない状態でした・・・。

2. マニュアルセットアップに方法2を追記しました。
   手動でframeworkをビルドする方法です。
   マニュアルセットアップするならコチラの方が楽です。

Kannaとは?

Swift製のHTML/XMLパーサです。
他パーサとの違いは CSSセレクタでも要素抽出 ができるぐらいです。

元々はSwift-HTML-Parserという名前でした。
"SwiftでObjCコードを書き換えてみる(Objective-C-HTML-Parser)"
最近RubyのNokogiriを知って、似せる形で書き換えたのでついでに名前も変えました。

導入手順

※Swift2の場合はREADME.mdを参照してください。

CocoaPods

Podfile
use_frameworks!
pod 'Kanna'

$ pod install

Carthage

Cartfile
github "tid-kijyun/Kanna" >= 0.1.0

$ carthage update

マニュアルセットアップ(方法1)

  1. プロジェクトを選択して"Linked Frameworks and Libraries" に libxml2.dylib を追加
  2. ”Header Search Paths" に $(SDKROOT)/usr/include/libxml2 を追加
  3. Bridging Headerに下記を追加
  #import <libxml/HTMLtree.h>
  #import <libxml/xpathInternals.h>

Bridging Headerが無い場合は作成してください。
4. Souceフォルダ配下の下記ファイルをプロジェクトに追加

   Kanna.swift
   CSS.swift
   libxml/libxmlHTMLDocument.swift
   libxml/libxmlHTMLNode.swift
   libxml/libxmlParserOption.swift

マニュアルセットアップ(方法2)

出力される場所を見つけられるなら手動でframeworkをビルドする方法もあります。

  1. Kanna.xcworkspace をXcodeで開いてビルド
  2. 生成された Release-iphoneos ディレクトリ内の Kanna.framework をプロジェクトに登録

参考:Github Issue #28 Use in Projects

使い方

インポート

// マニュアルセットアップの場合は不要です。
import Kanna

Kannaオブジェクトを作成

HTMLは別途引っ張ってくる必要があります。(だいたいAlamofire使うので入れていません・・・)

let url = NSURL(string: "https://en.wikipedia.org/wiki/cat")
let data = NSData(contentsOfURL: url!)
let doc = HTML(html: data!, encoding: NSUTF8StringEncoding)

文字列から作成することもできます。

let html = "<html>...</html>"
let doc = HTML(html: html, encoding: NSUTF8StringEncoding)

CSSセレクタで特定の要素を抽出する

// aタグ と linkタグ を抽出
nodes = doc?.css("a, link")

実際使うとこんな感じです。

// HTML内のリンク(URL)を抜き出す
for node in doc!.css("a, link") {
    println(node["href"])  // href属性に設定されている文字列を出力
}

Xpathで特定の要素を抽出する(結果はCSSセレクタの場合と同じ)

// aタグ と linkタグ を抽出
nodes = doc?.xpath("//a | //link")
// HTML内のリンク(URL)を抜き出す
for node in doc!.xpath("//a | //link") {
    println(node["href"])  // href属性に設定されている文字列を出力
}

属性値で絞り込む

Wikipediaのコンテンツをスクレイピングする場合・・・

// cssセレクタ ver
let contentDivNode = doc?.body?.css("div#content div#bodyContent div#mw-content-text")

// xpath ver
let contentDivNode = doc?.body?.xpath("div[@id='content']/div[@id='bodyContent']/div[@id='mw-content-text']")

こう書いてもOKです(bodyを省略)

// cssセレクタ ver
let contentDivNode = doc?.css("div#content div#bodyContent div#mw-content-text")

// xpath ver
let contentDivNode = doc?.xpath("//div[@id='content']/div[@id='bodyContent']/div[@id='mw-content-text']")

細かい使い方

タイトルを取得する

doc?.title      //=> Optional("hoge title")

headノードを取得する

head: メソッドで取得できます

let head = doc?.head

// 下記でも同じ
let head = doc?.css("head").first

bodyノードを取得する

body: メソッドで取得できます

let body = doc?.body

// 下記でも同じ
let body = doc?.css("body").first

タグ名を取得する

tagName で取得できます。

let node = doc?.css("div").first
node?.tagName   //=> Optional("div")

属性値を取得する

["ATTR_NAME"] で取得できます。

let node = doc?.css("a[href]").first
node?["href"]   //=> Optional("http://...")

HTMLを取得する

toHTML で取得できます。

let node = doc?.css("div").first
node?.toHTML    //=> Optional("<div...</div>")

タグの中身を取得する

innerHTML で取得できます。

let node = doc?.css("div").first
node?.innerHTML    //=> Optional("...")

その他

ご質問・ご指摘ありましたらお願いします。
プルリクも大歓迎です!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away