Swift製HTMLパーサ「Kanna」


@shu223 さんのpost ”[手軽に使えるSwift製HTMLパーサ「Ji」](http://qiita.com/shu223/items/86df55788f6b12d00fda)” に名前が出ていたので
Kannaも紹介記事を書いてみます。

Github: [Kanna](https://github.com/tid-kijyun/Kanna)(鉋)

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

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

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

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

## 導入手順
※Swift2の場合は[README.md](https://github.com/tid-kijyun/Kanna#swift2-xcode-beta)を参照してください。

### CocoaPods

```ruby:Podfile
use_frameworks!
pod 'Kanna'
```

` $ pod install `


### Carthage

```ruby:Cartfile
github "tid-kijyun/Kanna" >= 0.1.0
```

` $ carthage update`

### マニュアルセットアップ（方法１）

1. プロジェクトを選択して"Linked Frameworks and Libraries" に `libxml2.dylib` を追加
1. ”Header Search Paths" に `$(SDKROOT)/usr/include/libxml2` を追加
1. Bridging Headerに下記を追加

  ```objective-C
  #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
   ```

### マニュアルセットアップ（方法２）
出力される場所を見つけられるなら手動でframeworkをビルドする方法もあります。

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

参考：Github Issue #28 [Use in Projects](https://github.com/tid-kijyun/Kanna/issues/28#issuecomment-136850443)

## 使い方
#### インポート
```swift 
// マニュアルセットアップの場合は不要です。
import Kanna
```


#### Kannaオブジェクトを作成
HTMLは別途引っ張ってくる必要があります。(だいたいAlamofire使うので入れていません・・・)

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

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

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

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

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

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

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

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

```swift
// aタグ　と linkタグ を抽出
nodes = doc?.xpath("//a | //link")
```

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

#### 属性値で絞り込む
Wikipediaのコンテンツをスクレイピングする場合・・・

```swift
// 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を省略)

```swift
// 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']")
```

## 細かい使い方

#### タイトルを取得する

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

#### headノードを取得する
`head:` メソッドで取得できます

```swift
let head = doc?.head

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

#### bodyノードを取得する
`body:` メソッドで取得できます

```swift
let body = doc?.body

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

#### タグ名を取得する
`tagName` で取得できます。

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

#### 属性値を取得する
`["ATTR_NAME"]` で取得できます。

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

#### HTMLを取得する
`toHTML` で取得できます。

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

#### タグの中身を取得する
`innerHTML` で取得できます。

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

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