クソiOSアプリ開発〜Swiftでスクレイピングしてみた〜

#はじめに
どうも。
アドベントカレンダーを書くにあたって、今話題？のITP2.0について解説するかクソアプリを作るか迷ったんですが、クソアプリにしました。
###ITP2.0について少し説明すると、、、
ITPとはApple製端末の標準ブラウザであるSafariに搭載されている機能で、
ドメインをまたいで利用される3rd party Cookieの働きを抑制する機能です。
このITPのバージョン2.0以降から対象の3rd party Cookieが即時破棄される仕様になり、web広告業界が頭を悩ませてるんだってよ。

身近なもので言うと、全然関係ないサイトで過去に閲覧した内容の広告が表示される怪奇現象みたいな怖いアレあるじゃないですか。
アレをブロックしてくれたりする機能です。気になる方はググってみてください。
#牛丼の値段をスクレイピングするアプリ
前置きが長いわ！
ってことで、本題に入りましょう。SwiftでiOSアプリを作っていきます。
クソアプリ作成にあたり、せっかくなら現場で得たWeb系知識の要素を取り入れようということで、スクレイピングを実装しよう！ってなりました。
###スクレイピングとは
すごく適当に説明するとWebサイトから情報を抽出することです。
###なんで牛丼？
おそらくスクレイピング対象として面白いのはディズニーのアトラクションの待ち時間とかかな〜と思うんですけどお、すでにそういうアプリ存在してるじゃないですかあ〜。そういった中で割と変動しがちな値って牛丼の値段かなあと思っｔ
#作ります。

```swift:Gyudon.swift
import UIKit
//牛丼オブジェクト
class Gyudon: NSObject {
    var size: String = ""
    var price: String = ""
}
```

```GyudonPriceTableViewController.swift
import UIKit
//HTTP通信してくれるやつ
import Alamofire
//スクレイピングしてくれるやつ
import Kanna

class GyudonPriceTableViewController: UITableViewController {
    var beefbowl = [Gyudon]()
    override func viewDidLoad() {
        super.viewDidLoad()
        self.getGyudonPrice()
    }
    func getGyudonPrice() {
    //スクレイピング対象のサイトを指定
    Alamofire.request("https://www.yoshinoya.com/menu/gyudon/gyu-don/").responseString { response in
            if let html = response.result.value {
                if let doc = try? HTML(html: html, encoding: .utf8) {
                    
                    // 牛丼のサイズをXpathで指定
                    var sizes = [String]()
                    for link in doc.xpath("//th[@class='menu-size']") {
                        sizes.append(link.text ?? "")
                    }
                    
                    //牛丼の値段をXpathで指定
                    var prices = [String]()
                    for link in doc.xpath("//td[@class='menu-price']") {
                        prices.append(link.text ?? "")
                    }
                    
                    //牛丼のサイズ分だけループ
                    for (index, value) in sizes.enumerated() {
                        let gyudon = Gyudon()
                        gyudon.size = value
                        gyudon.price = prices[index]
                        self.beefbowl.append(gyudon)
                    }
                    self.tableView.reloadData()
                }
            }
        }
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.beefbowl.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)

        let gyudon = self.beefbowl[indexPath.row]
        cell.textLabel?.text = gyudon.size
        cell.detailTextLabel?.text = gyudon.price
        
        return cell
    }
}
```


吉野家の牛丼のサイズと値段を抽出します。
Xpathはデベロッパーツールを使うなりして取得しましょう。

#起動！
完成したアプリをXcodeのシミュレーターで起動してみました。
![CE0B7BEB-9500-428F-AEF6-D67CA0F3488E.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554106/3ba7a477-5b6b-8975-ad43-a11981b5e672.jpeg)

いえい！吉野家の牛丼の値段をいつでも確認できるアプリが出来上がりました！
吉野家Webサイトのhtml構造が変わらない限り値段が変わっても最新の値段を取得してくれます！

###なんかしょぼくね...？
しょぼすぎて草。
だからクソアプリだって言ったじゃないですかあ〜
本当はすき家と松屋も見れるようにして完全なる牛丼プライスチェッカーとするつもりだったんですが、
すき家の牛丼のサイズが上手くスクレイピングできなかったため断念。
(他にもスキル不足で実装できなかったものがいくつか...)

####というわけで
アドベントカレンダー終盤にとんでもないクオリティで恥をさらしつつ来年はもっとすごいアプリ作るぞーと意気込んで締めたいと思います。

お昼ご飯だいたい吉野家いきがち杉本でした〜。