ふととあるゲームの設置店舗を地図上にプロットしたくなりました。
地図描画には geopandas が良さそうです。
geopandas を使うまで
ここが一番厄介。
pip install だとすんなりいかないので conda install からやる必要があります。
Anaconda をインストール。
https://www.anaconda.com/products/individual
Anaconda Prompt を実行。
$ conda install geopandas
でインストールできるという触れ込みですが・・
$ Collecting package metadata (current_repodata.json): done
$ Solving environment: failed with initial frozen solve. Retrying with flexible solve.
こうなってインストールが完了しない。
専用環境を用意して切り替えてインストールすればいける。
$ conda create -n geo_env
$ conda activate geo_env
$ conda config --env --add channels conda-forge
$ conda config --env --set channel_priority strict
$ conda install python=3 geopandas
この状態で geosample.py が実行できるハズ。(専用環境は geo_env)
$ python geosample.py
VisualStudioCodeで起動したい場合はちょっとだけ厄介。
まずAnaconda Navigaterを起動。
Applications on を geo_env にする。
次に Visual Studio Code の Launch で起動。
左下の「Python 3.9.5 64-bit」をクリックして
「Python 3.9.7 64-bit (‘geo_env’:conda )」を選択。(バージョンは人によって異なる)
これで使用するpythonを切り替えることができ、実行すれば起動できる。
地図上にマーカーをプロット
設置店舗一覧から住所を取得、その住所を元に経度・緯度を求める。
pyファイルを分けているのは「住所から経度緯度を求めるサイトのAPI制限」があるため、一度ファイルに書き出すようにしている。
$ python wonderOsaka.py
# -*- coding: utf-8 -*-
import re
import time
import traceback
import chromedriver_binary
import requests
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def coordinate(address):
# 検索の頻度を、10秒に1回程度に抑えてください。
time.sleep(10)
payload = {'q': address}
html = requests.get('http://www.geocoding.jp/api/', params=payload)
soup = BeautifulSoup(html.content, "html.parser")
if soup.find('error'):
raise ValueError(f"Invalid address submitted. {address}")
latitude = soup.find('lat').string
longitude = soup.find('lng').string
return [latitude, longitude]
if __name__ == "__main__":
options = Options()
# ヘッドレスモードで実行する場合
options.add_argument("--headless")
driver = webdriver.Chrome(options=options)
# 取得先URLにアクセス
url = 'https://wonder.sega.jp/store/#!/area:5,pref:4'
driver.get(url)
# コンテンツが描画されるまで待機
time.sleep(5)
# ファイル
f = open('wonderOsaka.txt','w', encoding='UTF-8')
# 店舗情報取得
trs = driver.find_elements_by_class_name("Store")
index = 1
length = len(trs)
for tr in trs:
print(str(index) + "/" + str(length))
storeName = tr.find_elements_by_css_selector(".TextLink.Store-name")
storeAddr = tr.find_elements_by_css_selector(".Store-addr")
if len(storeName) > 0 and len(storeAddr) > 0:
latlons = coordinate(storeAddr[0].text)
lat = latlons[0]
lon = latlons[1]
f.write(storeName[0].text + "\t" + storeAddr[0].text+ "\t" + lat + "\t" + lon + "\n")
index = index + 1
f.close()
# プラウザを閉じる
driver.quit()
ファイルを読み込み、プロットして完成。
japan.geojson は https://github.com/dataofjapan/land から取得。
$ python geocoding.py
# -*- coding: utf-8 -*-
import csv
import geopandas as gpd
import matplotlib.pyplot as plt
if __name__ == "__main__":
# リストを読み込む
# csvファイル
csv_file = open("wonderOsaka.txt", "r", encoding="UTF-8", errors="", newline="" )
# リスト形式
fcsv = csv.reader(csv_file, delimiter="\t", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
list_of_rows = list(fcsv)
# 地図データ読み込み
df = gpd.read_file('japan.geojson')
with plt.style.context("ggplot"):
# 表示範囲を大阪府のみにする
df[df['nam_ja'] == '大阪府'].plot(figsize=(8,8), edgecolor='#444', facecolor='white', linewidth = 0.5)
index = 1
length = len(list_of_rows)
for row in list_of_rows:
print(str(index) + "/" + str(length) )
index = index + 1
# 地図にプロット
#lon = 135.499465
#lat = 34.726033
lon = float(row[3])
lat = float(row[2])
plt.scatter(lon, lat, marker='o', s=20, color="green", alpha=0.8, linewidths = 2)
# 保存
plt.savefig("map-300dpi.png", format="png", dpi=300, bbox_inches='tight', pad_inches=0)
# 表示
plt.show()