Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What are the problem?

posted at

CommonLispでOpenWeatherMapを使って気象データを取得してみる

はじめに

OpenWeatherMap は現在の天気や予測履歴を含む各種気象データの無料APIを提供しているオンラインサービスです
これをCommonLispで使ってみます

事前準備

手始めに OpenWeatherMap のページにアクセスし、サインアップしてAPI Keyを取得

API Keyを取得したらスペシャル変数として定義しておく

(defparameter *api-key* "Your API Key")

今回は Current weather data に書かれている通りに現在の気象データを取得してみようと思うので、そのベースURLをスペシャル変数として定義しておく

(defparameter *base-url* "http://api.openweathermap.org/data/2.5/weather")

HTTPクライアントとして dexador を使用するのでロードしておく

(ql:quickload :dexador)

都市名で取得

とりあえず 東京都 を指定してみる
都市名で取得する場合のクエリパラメータは以下のように指定する

q={city name}
q={city name},{state code}
q={city name},{state code},{country code}

今回は以下のように定義しておく

(defparameter *city-name* "Tokyo,JP")

これで準備完了、早速取得してみる

(dex:get (format nil "~A?q=~A&appid=~A" *base-url* *city-name* *api-key*))
取得結果
"{\"coord\":{\"lon\":139.69,\"lat\":35.69},\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}],\"base\":\"stations\",\"main\":{\"temp\":282.15,\"feels_like\":277.24,\"temp_min\":281.48,\"temp_max\":283.15,\"pressure\":1026,\"humidity\":61},\"visibility\":10000,\"wind\":{\"speed\":4.6,\"deg\":20},\"clouds\":{\"all\":20},\"dt\":1606765942,\"sys\":{\"type\":1,\"id\":8074,\"country\":\"JP\",\"sunrise\":1606771962,\"sunset\":1606807693},\"timezone\":32400,\"id\":1850144,\"name\":\"Tokyo\",\"cod\":200}"
200
#<HASH-TABLE :TEST EQUAL :COUNT 9 {1002445B13}>
#<QURI.URI.HTTP:URI-HTTP http://api.openweathermap.org/data/2.5/weather?q=Tokyo,JP&appid=6bee98cb406419564595b5c7aa0a4a78>
#<SB-SYS:FD-STREAM for "socket 192.168.11.6:48504, peer: 178.128.25.248:80" {1002443523}>

色々ごちゃっと取れたけど、とりあえず使うのは最初のJSONデータだけ
JSONデータの内容の詳細は Weather fields in API response に記載されている

JSONのままだとCommonLispでは使いづらいので、連想リストに変換する
そのために jonathan をロードする

(ql:quickload :jonathan)

もう一回取得

(jojo:parse
 (dex:get (format nil "~A?q=~A&appid=~A" *base-url* *city-name* *api-key*))
 :as :alist)
取得結果
(("cod" . 200) ("name" . "Tokyo") ("id" . 1850144) ("timezone" . 32400)
 ("sys" ("sunset" . 1606807693) ("sunrise" . 1606771962) ("country" . "JP")
  ("id" . 8074) ("type" . 1))
 ("dt" . 1606765942) ("clouds" ("all" . 20))
 ("wind" ("deg" . 20) ("speed" . 4.6)) ("visibility" . 10000)
 ("main" ("humidity" . 61) ("pressure" . 1026) ("temp_max" . 283.15)
  ("temp_min" . 281.48) ("feels_like" . 277.24) ("temp" . 282.15))
 ("base" . "stations")
 ("weather"
  (("icon" . "02n") ("description" . "few clouds") ("main" . "Clouds")
   ("id" . 801)))
 ("coord" ("lat" . 35.69) ("lon" . 139.69)))

さらに、連想リストを操作するのに便利なユーティリティ assoc-utils があるのでこれもロードする

(ql:quickload :assoc-utils)

取得した現在の気象データをスペシャル変数として定義しておく

(defparameter *current-weather-data*
  (jojo:parse
   (dex:get (format nil "~A?q=~A&appid=~A" *base-url* *city-name* *api-key*))
   :as :alist))

以下のように各要素にアクセスできる

(assoc-utils:aget *current-weather-data* "name")
取得結果
"Tokyo"

時刻はUnix時間なので時間操作ライブラリ local-time をロードして

(ql:quickload :local-time)

unix-to-timestamp してやれば

(local-time:unix-to-timestamp (assoc-utils:aget *current-weather-data* "dt"))
取得結果
@2020-12-01T04:52:22.000000+09:00

見慣れた表示になる

天気情報 weather の中の main にアクセスするには以下のようにする

(assoc-utils:aget
 (first (assoc-utils:aget *current-weather-data* "weather"))
 "main")
取得結果
"Clouds"

曇りのようです

City IDで取得

東京の City ID は 1850147

(defparameter *city-id* "1850147")

City IDで取得する場合のクエリパラメータは以下のように指定する

id={city id}
(jojo:parse
 (dex:get (format nil "~A?id=~A&appid=~A" *base-url* *city-id* *api-key*))
 :as :alist)
取得結果
(("cod" . 200) ("name" . "Tokyo") ("id" . 1850147) ("timezone" . 32400)
 ("sys" ("sunset" . 1606807693) ("sunrise" . 1606771962) ("country" . "JP")
  ("id" . 8074) ("type" . 1))
 ("dt" . 1606765634) ("clouds" ("all" . 20))
 ("wind" ("deg" . 350) ("speed" . 4.6)) ("visibility" . 10000)
 ("main" ("humidity" . 66) ("pressure" . 1026) ("temp_max" . 284.15)
  ("temp_min" . 281.48) ("feels_like" . 277.74) ("temp" . 282.42))
 ("base" . "stations")
 ("weather"
  (("icon" . "02n") ("description" . "few clouds") ("main" . "Clouds")
   ("id" . 801)))
 ("coord" ("lat" . 35.69) ("lon" . 139.69)))

結果は大体同じ

緯度経度で取得

東京駅の緯度経度は 35.681236 139.767125 なのでこれを使う

(defparameter *lat* "35.681236")
(defparameter *lon* "139.767125")

緯度経度で取得する場合のクエリパラメータは以下のように指定する

lat={lat}&lon={lon}
(jojo:parse
 (dex:get (format nil "~A?lat=~A&lon=~A&appid=~A" *base-url* *lat* *lon* *api-key*))
 :as :alist)
取得結果
(("cod" . 200) ("name" . "Marunouchi") ("id" . 1857654) ("timezone" . 32400)
 ("sys" ("sunset" . 1606807675) ("sunrise" . 1606771941) ("country" . "JP")
  ("id" . 8074) ("type" . 1))
 ("dt" . 1606765782) ("clouds" ("all" . 20))
 ("wind" ("deg" . 350) ("speed" . 4.6)) ("visibility" . 10000)
 ("main" ("humidity" . 66) ("pressure" . 1026) ("temp_max" . 284.15)
  ("temp_min" . 281.48) ("feels_like" . 277.66) ("temp" . 282.35))
 ("base" . "stations")
 ("weather"
  (("icon" . "02n") ("description" . "few clouds") ("main" . "Clouds")
   ("id" . 801)))
 ("coord" ("lat" . 35.68) ("lon" . 139.77)))

name が何故か Marunouchi になってる

郵便番号で取得

東京タワーの郵便番号 105-0011 を使ってみる

郵便番号で取得する場合のクエリパラメータは以下のように指定する

zip={zip code},{country code}
(defparameter *zip-code* "105-0011,JP")
(jojo:parse
 (dex:get (format nil "~A?zip=~A&appid=~A" *base-url* *zip-code* *api-key*))
 :as :alist)
取得結果
(("cod" . 200) ("name" . "Shibakouen") ("id" . 0) ("timezone" . 32400)
 ("sys" ("sunset" . 1606807683) ("sunrise" . 1606771943) ("country" . "JP")
  ("id" . 8074) ("type" . 1))
 ("dt" . 1606766365) ("clouds" ("all" . 20))
 ("wind" ("deg" . 20) ("speed" . 4.6)) ("visibility" . 10000)
 ("main" ("humidity" . 61) ("pressure" . 1026) ("temp_max" . 283.15)
  ("temp_min" . 281.48) ("feels_like" . 276.9) ("temp" . 281.86))
 ("base" . "stations")
 ("weather"
  (("icon" . "02n") ("description" . "few clouds") ("main" . "Clouds")
   ("id" . 801)))
 ("coord" ("lat" . 35.66) ("lon" . 139.75)))

name が何故か Shibakouen になってる

最後に

こういうのが簡単に無料で使えるのは良いですね
色々応用できそうです

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
1
Help us understand the problem. What are the problem?