無料利用可能なAPIで住所から緯度経度情報を得る

#はじめに
本記事は以下の取り組みの一環です。

https://qiita.com/sckln/items/9af07be8df426cbcdb36

#やりたいこと

住所を示すテキストデータから緯度、経度を得たい。それを使ってfoliumで可視化したい。（が、foliumについて深追いするのはまた今度）

#手順

住所→緯度経度とするには住所の表記揺れも気になるし、そもそも１対１対応していないので、住所から代表点を得られるのかどうかも心配です。
決して網羅的な調査はしていないものの、住所から郵便番号を経由したら上手くいきそうな勘が働き、結果的にはうまくいきました。１パスの方法もあるかもしれません。

1. 番地情報を落として、町域単位（市区町村の次の粒度のやつ）にする。
1. 住所から郵便番号をGet by [zipcoda.net](https://zipcoda.net/doc)
1. 郵便番号から代表点の緯度経度をGet by [HeartRailsGeoAPI](https://geoapi.heartrails.com/api.html#town)

説明を読み返すとHeartRails１つで行けたような気もしますが、お好みで。

#実践

###1. 町域単位にする

```py
import re
address='東京都千代田区永田町１丁目７−１'#ちなみに国会議事堂です
address=re.sub("[１-９].*","", address)
print(address)
```

>東京都千代田区永田町

これでもよいのですが、実際にはpandas.DataFrameのcolumnに入った大量のデータを処理するので、こんな感じになります。数字が半角全角混在していることを想定した処理です。

```py
df['address']=df['address'].str.replace("[１-９].*","").str.replace("[1-9].*","")
```

###2. zipcoda.net

```py
import re
import requests
import json
address='東京都千代田区永田町１丁目７−１'#ちなみに国会議事堂です
address=re.sub("[１-９].*","", address)
url='http://zipcoda.net/api?address='+address
r = requests.get(url)
print(r.json())
```

>{
    'status': 200, 
    'length': 45, 
    'items': [
        {'zipcode': '1000014',
        'pref': '東京都',
        'state_name': '東京都',
        'components': [
            '東京都',
            '千代田区',
            '永田町'],
        'address': '千代田区永田町'
        },
        {'zipcode': '1006101',
        'pref': '東京都',
        'state_name':
        '東京都',
        'components': [
            '東京都',
            '千代田区',
            '永田町山王パークタワー1階'],
        'address': '千代田区永田町山王パークタワー1階'
        }
(後略)
}

1フロア毎に郵便番号を持っている山王パークタワーはさておき、このように辞書形式でデータが得られます。入れ子構造になっていて一目で把握するのはちょっと大変ですが、知りたいのは'items'の1つ目の'zipcode'。

```py
print(r.json()['items'][0]['zipcode'])
```

>1000014

###3. HeartRailsGeoAPI
多機能なAPIですが、SerchByPostalというのを使います。

```py
url = 'http://geoapi.heartrails.com/api/json?method=searchByPostal&postal='
postal=str(1000014)#先ほど上で取得した郵便番号(int→strに型変換しておく)
res_dict = requests.get(url+postal).json()['response']['location'][0]
print(res_dict['x'],res_dict['y'])
```

>139.745749 35.676328

なお、1丁目で代表する考えです。さらっと流しましたが、これも、欲しい経度緯度を取得するには``requests.get(url+posatal).json()``で得られるdict形式のデータの構造をよく眺めないといけません。notebook環境でprintとしても１行で返ってくるので何かしらのエディタにコピペして把握しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1381159/a30e6116-58e2-d1b6-e3ce-e1f6e11c937f.png)

#可視化

なぜ緯度経度を取得したのかといえば、地図上にマークしたいからです。foliumも奥が深そうなので、もう少し勉強してまた別の機会に詳しく紹介したいです。

```py
import re
import requests
import json
import folium

address='東京都千代田区永田町１丁目７−１'
address=re.sub("[１-９].*","", address)

url1='http://zipcoda.net/api?address='+address
postal=str(requests.get(url1).json()['items'][0]['zipcode'])

url2 = 'http://geoapi.heartrails.com/api/json?method=searchByPostal&postal='
res_dict = requests.get(url2+postal).json()['response']['location'][0]
x=float(res_dict['x'])
y=float(res_dict['y'])

map=folium.Map(location=[y, x], width=800, height=800, zoom_start=16, control_scale=True, tiles='OpenStreetMap')
folium.Marker(location=[y, x]).add_to(map)

map
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1381159/cfd86232-4e5e-b912-2abd-4ddfacd1338a.png)