OpenWeatherMapで郵便番号が使えないときのアプローチ

OpenWeatherMap

OpenWeatherMapは、開発者に、現在の天候や予測履歴を含む各種気象データを提供する無料APIです(一部有料あり)。

使い方については、記事が沢山出ているので、参考程度にQiitaのリンクを貼っておきます。

qiita.com

郵便番号を指定してデータを取得する

zipパラメータを指定することで郵便番号指定検索ができます。

import requests
url = https://api.openweathermap.org/data/2.5/forecast
params = {
    "APPID" : API_KEY,
    "units" : "metric",
    "zip" : "100-0001,jp"
}
res = requests.get(url,params=params)

APPIDAPI keyです。取得方法については、多くの記事で紹介されているので省略します。

エンドポイント(url)にhttps://api.openweathermap.org/data/2.5/forecastを指定すると、5日間分の3時間予報が取得できます。

https://api.openweathermap.org/data/2.5/weatherを指定すると、現在の天候が取得できます。

郵便番号を指定してもデータが取得できないとき

ここからがメインです。

例えば郵便番号に 100-0001(東京都千代田区千代田)を指定すると、データが取得できます。

ただし、100-0000(東京都千代田区)を指定すると、取得できません。

{
    "cod": "404",
    "message": "city not found"
}

この問題・解決策を記載している記事が少なかったので、一つのアプローチとして、HeartRailsGeo APIを使用して緯度・経度を算出した後に、緯度経度から気象情報を取得するという方法を紹介します。 他には、そもそも郵便番号を利用しない(CityCode等の他パラメータを用いて検索)などの方法があります。
この記事は、どうしても郵便番号が使いたい人向けです。

HeartRailsGeo API

「HeartRails Geo API」 は、郵便番号/住所/緯度経度データ等の地理情報を、XMLJSON(P) 形式の API により無料でご提供させていただくサービスです。

API は商用、非商用を問わず、無料でご利用になれます。

url : http://geoapi.heartrails.com/api.html

この中の、郵便番号から郵便番号による住所検索 APIを使用します。

import requests
url = http://geoapi.heartrails.com/api/json
params = {
    "method" : "searchByPostal",
    "postal" : "<郵便番号>" (例:1000000)
}
res = requests.get(url,params=params)

郵便番号1000000を指定したときのレスポンスは次のようなものです。

x : 経度,y :緯度

{
    "response": {
        "location": [
            {
                "city": "千代田区",
                "city_kana": "ちよだく",
                "town": "(その他)",
                "town_kana": "(そのた)",
                "x": "139.754927",
                "y": "35.68576",
                "prefecture": "東京都",
                "postal": "1000000"
            }
        ]
    }
}

緯度経度を指定してOpenWeatherMapから情報を取得する

ここで取得した緯度経度を使います。

# res : 郵便番号から郵便番号による住所検索 APIのレスポンス
longitude = res["response"]["location"][0]["x"]
latitude = res["response"]["location"][0]["y"]
url='https://api.openweathermap.org/data/2.5/weather'
params={
    "lon":longitude,
    "lat":latitude,
    "units":"metric",
    "APPID":APIKEY
}
res = requests.get(url,params=params)

これで(ほぼすべての郵便番号について、正しい情報が)取得できました。

注意点

郵便番号が被る地域があります。

この記事を見ると、よくわかります。

qiita.com

郵便番号は必ず1つの町名に紐づいているわけではない
市区町村をまたいで同じ郵便番号を持つケースがある
市区町村はおろか県を飛び越えて同じ郵便番号を持ちうるケースがある

例えば、6180000を指定して、住所検索APIにリクエストを送ると次のようなレスポンスが返ってきます。

{
    "response": {
        "location": [
            {
                "city": "乙訓郡大山崎町",
                "city_kana": "おとくにぐんおおやまざきちょう",
                "town": "(その他)",
                "town_kana": "(そのた)",
                "x": "135.688862",
                "y": "34.904159",
                "prefecture": "京都府",
                "postal": "6180000"
            },
            {
                "city": "三島郡島本町",
                "city_kana": "みしまぐんしまもとちょう",
                "town": "(その他)",
                "town_kana": "(そのた)",
                "x": "135.667274",
                "y": "34.902399",
                "prefecture": "大阪府",
                "postal": "6180000"
            }
        ]
    }
}

取得できるデータは正しいですが、上記の通り、安直に

longitude = res["response"]["location"][0]["x"]
latitude = res["response"]["location"][0]["y"]

のように0番目を指定すると誤った情報を提供する可能性があります。

まとめ

OpenWeatherMapで郵便番号を指定してリクエストをする方法と、できないときのアプローチとしてHeartRailsGeo APIを使用して緯度・経度を算出した後に、緯度経度から気象情報を取得する方法を紹介しました。

しかし、日本の郵便番号の設定上、誤った情報を提供する可能性があることに注意する必要があります。

郵便番号が被っていない地域に対してサービスを提供するような場合、今回のアプローチは有効ですが、サービス提供先の地域の郵便番号が複数の地域に及ぶ場合は、今回の方法は使えません。