jqコマンドで無料の気象情報取得APIと遊んでみる

# はじめに

最近、JSONデータに触れることが多くなり、jqコマンドの存在を知りました。使ってみると、jqコマンドは超便利そうなんだけど、使いこなせてない気がするので何かで遊びながら覚えたい。そこで、jqコマンドと、無料で利用できるOpenWeatherMapの気象情報取得APIから情報を取得して戯れてみました。


# 環境

* Mac OS X 10.10.5
* jq-1.5

`jq`コマンドはbrewでインストールしました。地味に、バージョン1.4と1.5だとコマンドの動作が違うところがあるらしいので、思ったように動かない場合は最新版にしてみること。

```bash
$ brew install jq
$ jq --version
jq-
```

あれ、バージョンが表示されなかったですけど、バージョン1.5です。


# 利用するデータ

## 取得サイト

今回はここを利用させてもらうことにしました。

* [OpenWeatherMap](http://openweathermap.org/)


## API

他にも色々あるみたいですがとりあえず。

* [過去データ取得API](http://openweathermap.org/forecast16)

```bash:API
api.openweathermap.org/data/2.5/forecast/daily?q={city name},{country code}&cnt={cnt}
```


## 実行例

* 横浜市(yokohama)の気象データ3日分

```bash
$ curl -s "http://api.openweathermap.org/data/2.5/forecast/daily?q=yokohama,jp&cnt=3"
{"city":{"id":2127436,"name":"Yokohama","coord":{"lon":141.25,"lat":41.083328},"country":"JP","population":0},"cod":"200","message":0.0164,"cnt":3,"list":[{"dt":1442887200,"temp":{"day":289.22,"min":289.22,"max":289.22,"night":289.22,"eve":289.22,"morn":289.22},"pressure":1012.25,"humidity":98,"weather":[{"id":800,"main":"Clear","description":"sky is clear","icon":"01n"}],"speed":1.51,"deg":251,"clouds":0},{"dt":1442973600,"temp":{"day":297.24,"min":284.3,"max":297.24,"night":284.3,"eve":291.45,"morn":286.25},"pressure":1011.34,"humidity":63,"weather":[{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"}],"speed":1.22,"deg":347,"clouds":0},{"dt":1443060000,"temp":{"day":295.87,"min":282.74,"max":295.87,"night":283.9,"eve":289.68,"morn":282.74},"pressure":1008.67,"humidity":63,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"speed":1.67,"deg":116,"clouds":44}]}
```

jqコマンドで遊ぶ時に、何度もAPIを実行するのは申し訳ない気がするので、出力結果をファイルに落としておきました。ファイルには上記の実行結果がそのまま保存されています。

```bash
$ curl -s "http://api.openweathermap.org/data/2.5/forecast/daily?q=yokohama,jp&cnt=3" > weather_yokohama.json
```


# jqコマンド

JSON形式のデータを見たりフィルタしたりするのに非常に便利。強力すぎて使いこなすのが難しい。上手く使えるようになると、便利すぎて他の言語でパースするのが面倒臭くなりそうで怖いです。


## 基本

いきなり欲しいフィルタを書くのはレベル高すぎるのでまずはここから。これだけでも、十分人間にやさしい表示になります。

```bash
$ cat weather_yokohama.json | jq "."
{
  "city": {
    "id": 2127436,
    "name": "Yokohama",
    "coord": {
      "lon": 141.25,
      "lat": 41.083328
    },
    "country": "JP",
    "population": 0
  },
(略)
}
```


## フィールド指定

欲しいフィールドだけを指定して表示してみます。指定したいフィールドが、オブジェクトか配列か値かあたりを気をつける必要がありそうです。

```bash
$ cat weather_yokohama.json | jq '.city.name'
"Yokohama"
```


## 配列内のフィールド指定

配列の中にある`.dt`フィールドを取り出してみます。ここでは、`.list[]`は配列、`.dt`は値というフィールドになっているようです。

```bash
$ cat weather_yokohama.json | jq '.list[].dt'
1442887200
1442973600
1443060000
```


## 指定フォーマット出力

取り出したデータは日本語の中に混ぜたり、好きなフォーマットの中に埋めることができます。クォートが不要な場合、`jq`コマンドに`-r`オプションを付けることを忘れないように。また、`jq`コマンド内で`|`を使うことで複数の結果を順に処理させることができます。

```bash
$ cat weather_yokohama.json | jq -r '.list[].weather[] | "横浜市は\(.main)(\(.description))でした"'
横浜市はClear(sky is clear)でした
横浜市はClear(sky is clear)でした
横浜市はClouds(scattered clouds)でした
```


## データを使ってオブジェクト表示

データの中の値を使って、新たにキーとバリューのオブジェクトを作ってみます。キーは文字列である必要があるため、`tostring`を通しているてんに注意が必要です。このくらいできるようになると、JSONデータをパースして操作してる感あります。

```bash
$ cat weather_yokohama.json | jq '[.list[] | {(.dt | tostring): .weather[].main}]'
[
  {
    "1442887200": "Clear"
  },
  {
    "1442973600": "Clear"
  },
  {
    "1443060000": "Clouds"
  }
]

```


## テキスト出力

結果は、JSONオブジェクトではなく、テキストの結果として出力することも可能です。といっても、値埋め込みの出力フォーマットで出しているだけですが。

```bash
$ cat weather_yokohama.json | jq -r '.list[] | "\(.dt): \(.weather[].main)"'
1442887200: Clear
1442973600: Clear
1443060000: Clouds
```


# まとめ

最近はJSON形式でデータをやり取りしたり、保存したりすることが多いです。ログまでJSON形式ということもあります。JSONは簡単かつ構造化したデータを表現できて便利なんですかね。ただ、人には優しくないフォーマットなので、jqコマンドを使いこなして楽したいところ。


# 参考

* [ゼロから始めるjqチュートリアル - JSONを解析/自在に出力する](http://blog.serverfrog.jp/jq-tutorial/)