Python の overpass を用いて OpenStreetMap のデータをダウンロード
【概要】
Python の overpass パッケージを使用して、OpenStreetMap から地図データをダウンロードする方法を解説する。Google Map で緯度経度を調べ、Overpass API を通じてポイント(ノード)やライン(ウェイ)のデータを取得し、GeoJSON 形式で処理する手順を示す。
【その他情報】
本記事では MapQuery を用いて、指定範囲内のウェイ(線)と、それを構成するノード(点)をまとめて取得する。OpenStreetMap の3種類の要素は、取得後の GeoJSON では次のように表現される。
- ノード(点) → GeoJSON の
Point - ウェイ(線) → GeoJSON の
LineString - リレーション(複数要素の組み合わせ) → 形状に応じた複合的なジオメトリ
MapQuery で返る Point の多くは、ウェイを構成する中間ノードであり、タグ(属性)を持たない(properties が空 {} の)ものが多い。店舗や施設のように「タグの付いた点」だけが欲しい場合は、演習で扱うタグ指定のクエリを使う。
前提知識: Python の基本的な操作(変数、リスト、辞書、for 文など)を理解していることを前提とする。本記事のプログラムは Windows 上で動作し、GPU は不要である(CPU のみで動作する)。
利用上の注意: Overpass API には利用制限がある。短時間に大量のリクエストを送信すると、一時的にアクセスが制限される。制限に達すると HTTP エラーや例外が発生するため、連続して実行する場合は数秒の間隔を空ける。また、公開サーバーへのリクエストには User-Agent の指定が必須である(指定しないとアクセスがブロックされる場合がある)。User-Agent は実在のメールアドレスである必要はないが、サーバー運用者が問題発生時に判別できるよう、アプリケーション名と連絡可能な識別子を記載する。OpenStreetMap のデータは Open Database License (ODbL) の下で提供されており、利用時にはライセンス条件に従う。
【目次】
【関連する外部ページ】
- OpenStreetMap (https://www.openstreetmap.org):世界規模で利用できる無料のオンライン地図データベース。
- Overpass API(OpenStreetMap Wiki):OpenStreetMap のデータベースから条件を指定してデータを抽出する問い合わせインターフェース。
- overpass(PyPI):本記事で使用する Python ラッパーライブラリ。開発は Codeberg(codeberg.org/mvexel/overpass-api-python-wrapper)へ移行済み。
実行環境の準備
Python 3.12 のインストール
Pythonのインストールを行い、Pythonのプログラムを実行する環境を整える。扱う環境は、Windows搭載パソコンである。金子研究室では、Python 3.12.10を推奨する。
[Windows での Python 3.12 のインストール手順を見るには、ここをクリック]
Windows での Python 3.12 のインストール
以下のいずれかの方法でPython 3.12をインストールする。Pythonがインストール済みの場合、この手順は不要である。
方法 1:winget によるインストール
【インストールコマンドの実行方法】
管理者権限でコマンドプロンプトを起動する(手順:Windowsキーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。そして、コマンド全体をコマンドプロンプトにコピー&ペーストする。
--scope machine を指定することで、システム全体(全ユーザー向け)にインストールされる。このオプションの実行には管理者権限が必要である。インストール完了後、コマンドプロンプトを再起動するとPATHが反映される。
REM Python 3.12 をシステム領域にインストール
winget install --id Python.Python.3.12 -e --scope machine --silent --accept-source-agreements --accept-package-agreements --override "/quiet InstallAllUsers=1 PrependPath=1 Include_test=0 Include_pip=1 Include_launcher=1 InstallLauncherAllUsers=1 TargetDir=\"C:\Program Files\Python312\""
REM Python と Scripts を PATH 先頭に追加
powershell -NoProfile -Command "$p='C:\Program Files\Python312'; $s=\"$p\Scripts\"; $c=[Environment]::GetEnvironmentVariable('Path','Machine'); if((Test-Path $p) -and (';'+$c+';' -notlike \"*;$p;*\") -and (';'+$c+';' -notlike \"*;$s;*\")){[Environment]::SetEnvironmentVariable('Path',\"$p;$s;$c\",'Machine')}"
方法 2:インストーラーによるインストール
- Python公式サイト(https://www.python.org/downloads/)にアクセスし、「Download Python 3.x.x」ボタンからWindows用インストーラーをダウンロードする。
- ダウンロードしたインストーラーを実行する。
- 初期画面の下部に表示される「Add python.exe to PATH」にチェックを入れてから「Customize installation」を選択する。このチェックを入れ忘れると、コマンドプロンプトから
pythonコマンドを実行できない。 - 「Install Python 3.xx for all users」にチェックを入れ、「Install」をクリックする。
インストールの確認
コマンドプロンプトで以下を実行する。
python --version
バージョン番号(例:Python 3.12.x)が表示されればインストール成功である。「'python' は、内部コマンドまたは外部コマンドとして認識されていません。」と表示される場合は、インストールが正常に完了していない。
Python の開発環境 Visual Studio Code のインストールと Python 用の設定
Python の開発環境Visual Studio Code(プログラムを編集するソフトウェア。以下、VS Code)を整える。
[Windows での Visual Studio Code のインストールと Python 用の設定手順を見るには、ここをクリック]
Windows での Visual Studio Code のインストールと Python 用の設定手順
1. VS Code と拡張機能のインストール
以下のコマンドにより,既存の VS Code を削除し,全ユーザー共有の設定で再インストールしたうえで,拡張機能(VS Code に機能を追加するソフトウェア)をまとめて導入する.
【インストールコマンドの実行方法】
管理者権限でコマンドプロンプトを起動する(手順:Windows キーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。そして,コマンド全体をコマンドプロンプトにコピー&ペーストする。
インストールコマンド
REM ============================================================
REM Microsoft Visual Studio Code
REM ============================================================
winget uninstall -e --id Microsoft.VisualStudioCode --silent --disable-interactivity --accept-source-agreements
rmdir /s /q C:\ProgramData\vscode-extensions 2>nul
rmdir /s /q "%APPDATA%\Code" 2>nul
rmdir /s /q "%USERPROFILE%\.vscode" 2>nul
rmdir /s /q "%LOCALAPPDATA%\Microsoft\vscode-update" 2>nul
REM VS Code をシステム領域に新規インストール
winget install --scope machine --id Microsoft.VisualStudioCode -e --silent --accept-source-agreements --accept-package-agreements
REM 全ユーザー共有の拡張機能フォルダ
mkdir C:\ProgramData\vscode-extensions 2>nul
icacls "C:\ProgramData\vscode-extensions" /grant "Everyone:(OI)(CI)M" /T
REM スタートメニューのショートカットを --extensions-dir 付きで再作成
rmdir /s /q "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio Code" 2>nul
del "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio Code.lnk" 2>nul
powershell -NoProfile -Command "$s=New-Object -ComObject WScript.Shell; $lnk=$s.CreateShortcut('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio Code.lnk'); $lnk.TargetPath='C:\Program Files\Microsoft VS Code\Code.exe'; $lnk.Arguments='--extensions-dir \"C:\ProgramData\vscode-extensions\"'; $lnk.Save()"
REM ショートカットの検証
powershell -NoProfile -Command "$s=New-Object -ComObject WScript.Shell; $lnk=$s.CreateShortcut('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio Code.lnk'); Write-Host 'TargetPath:' $lnk.TargetPath; Write-Host 'Arguments:' $lnk.Arguments"
REM ファイル / フォルダ右クリックの「Code で開く」を登録
reg add "HKLM\SOFTWARE\Classes\*\shell\VSCode\command" /ve /d "\"C:\Program Files\Microsoft VS Code\Code.exe\" --extensions-dir \"C:\ProgramData\vscode-extensions\" \"%1\"" /f
reg add "HKLM\SOFTWARE\Classes\Directory\shell\VSCode\command" /ve /d "\"C:\Program Files\Microsoft VS Code\Code.exe\" --extensions-dir \"C:\ProgramData\vscode-extensions\" \"%1\"" /f
reg add "HKLM\SOFTWARE\Classes\Directory\Background\shell\VSCode\command" /ve /d "\"C:\Program Files\Microsoft VS Code\Code.exe\" --extensions-dir \"C:\ProgramData\vscode-extensions\" \"%V\"" /f
REM --extensions-dir 付きで起動する code.cmd ラッパを作成
REM (%* を echo で書くと対話的 cmd で失われるため、PowerShell で [char]37+'*' を書き出す)
powershell -NoProfile -Command "$pct=[char]37; $q=[char]34; $c='@echo off'+[char]13+[char]10+$q+'C:\Program Files\Microsoft VS Code\bin\code.cmd'+$q+' --extensions-dir '+$q+'C:\ProgramData\vscode-extensions'+$q+' '+$pct+'*'+[char]13+[char]10; [IO.File]::WriteAllText('C:\ProgramData\vscode-extensions\vscode.cmd',$c,[Text.Encoding]::ASCII)"
REM 拡張機能のインストール
set "CODE=C:\Program Files\Microsoft VS Code\bin\code.cmd"
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --uninstall-extension GitHub.copilot
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --uninstall-extension GitHub.copilot-chat
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension ms-python.python
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension ms-python.vscode-pylance
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension ms-python.debugpy
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension MS-CEINTL.vscode-language-pack-ja
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension saoudrizwan.claude-dev
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension rust-lang.rust-analyzer
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension tamasfe.even-better-toml
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension anthropic.claude-code
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension almenon.arepl
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --list-extensions --show-versions
echo === セットアップ完了 ===
2. Python インタプリタの選択
同一マシンに複数の Python がインストールされている場合,VS Code で使用する Python 本体(インタプリタ:Python プログラムを解釈・実行するソフトウェア)を選択する必要がある.
- コマンドパレット(コマンド名で機能を呼び出す VS Code の入力欄)を開く(
Ctrl+Shift+P) Python: Select Interpreterと入力する
- 表示される一覧から,使用する Python(例:
C:\Program Files\Python312\python.exe)を選択する.
Python プログラム実行手順
[Windows での Python プログラム実行手順を見るには、ここをクリック]
Windows での Python 実行手順(Visual Studio Codeを使用)
プログラムファイルの作成と保存
- 左サイドバーの「エクスプローラー」アイコン(
Ctrl+Shift+E)をクリックする
- 「NO FOLDER OPENED」(作業対象フォルダが未選択の状態)と表示される場合は,「Open Folder」をクリックし,プログラムを保存するフォルダを選択する
続いて「フォルダを信用するか」を確認する画面(フォルダ内のコードを実行してよいか確認する VS Code の仕組み)が表示されるので,チェックして Yes を選択する
- フォルダ名の右側に表示される「新しいファイル」アイコンをクリックする
- ファイル名(例:
aitask.py.ファイル名は何でも良い)を入力しEnterを押す.拡張子は.py(Python ファイルを示す拡張子)とする
- 実行したいコードを選択し,
Ctrl+Cでコピーする.VS Code のエディタ領域にCtrl+Vで貼り付ける Ctrl+Sで保存する
プログラムの実行
- エディタ右上の三角形「▷」アイコン(Run Python File:現在開いている Python ファイルを実行するボタン)をクリックする.または,エディタ上で右クリックし「ターミナルで Python ファイルを実行」を選択する
- VS Code 下部のターミナル(コマンドの入出力を表示する画面)に,実行結果(
print関数の出力等)が表示される
- tkinter(Python 標準の GUI ライブラリ)のファイル選択ダイアログを使うプログラムを実行した場合は,ダイアログが開くので対象画像を選択する
- VS Code 下部のターミナルで実行結果を確認する.OpenCV ウィンドウ(OpenCV が画像を表示するために開く専用ウィンドウ)が開いた場合はそちらも確認する.OpenCV ウィンドウは,マウスクリックでウィンドウをアクティブ(操作対象の状態)にしてからキーを押すと終了する
必要な Python ライブラリのインストール(Windows 上)
本記事で使用するライブラリは、Windows 用のビルド済みパッケージ(wheel)が配布されている。そのため C/C++ コンパイラのインストールは不要であり、pip install のみでインストールできる。
- 管理者権限でコマンドプロンプトを起動する
(手順:Windowsキーまたはスタートメニュー →
cmdと入力 → 右クリック → 「管理者として実行」)。 - 以下のコマンドを実行し、必要なライブラリをインストールする。
pip install -U --no-user overpass pip install -U --no-user geopandas
overpass は Overpass API からデータを取得するライブラリ、geopandas は取得した地理空間データを表形式で扱い、可視化や空間分析を行うライブラリである。
Google Map を用いて緯度経度を調べる
OpenStreetMap からデータをダウンロードするには、対象地域の緯度と経度の指定が必要である。ここでは Google Map を使用して座標を取得する。
- Google Map を開く。
- Google Map で任意の場所に移動する。
- 目的の場所で右クリックし、表示されたメニューの先頭にある緯度・経度の数値をクリックする(クリックするとクリップボードにコピーされる)。
- 緯度と経度の値を記録しておく。値は「緯度, 経度」の順で表示される。
Python を用いて OpenStreetMap のデータをダウンロードして処理する
Python プログラムの実行方法
Windows では、コマンドプロンプトで python ファイル名.py を実行するか、対話モード(python と入力して起動)に1行ずつ貼り付けて実行する。
OpenStreetMap のデータ構造: OpenStreetMap のデータは、ノード(点)、ウェイ(線)、リレーション(複数要素の組み合わせ)の3種類で構成される。ノードは緯度経度を持つ点で、店舗や交差点などを表す。ウェイは複数のノードを順に結んだ線で、道路や河川などを表す。各要素には タグ(キーと値のペア)が付与され、要素の種類や属性を示す(例:道路には highway=primary のようなタグが付く)。
- ダウンロードしたい地図の緯度と経度を設定し、データを取得する。
以下の Python プログラムを実行する。緯度と経度には、前節で取得した値を使用する。
MapQueryの引数は、取得範囲を示すバウンディングボックス(南端の緯度、西端の経度、北端の緯度、東端の経度)である。以下の例では、指定した座標を中心に約200m四方の範囲を取得する(0.001度は緯度方向で約111m、経度方向は緯度によって変わり、日本付近では約90m に相当する。高緯度ほど経度方向の実距離は短くなる)。API を生成する際は、アプリケーション名と連絡先を含む
user_agentを指定する(公開サーバーへのリクエストに必須)。ウェイ(線)を
LineStringとして取得するには、ウェイに座標(ジオメトリ)を付与する必要がある。これにはget()にverbosity="geom"を指定する。指定しない場合は既定のbody動作となり、ウェイに座標が付かずLineStringが得られないことがある。import overpass lat = 34.4461 lon = 133.2315 api = overpass.API(user_agent="MyMapApp (your-email@example.com)") # バウンディングボックス: (南緯, 西経, 北緯, 東経) map_query = overpass.MapQuery(lat - 0.001, lon - 0.001, lat + 0.001, lon + 0.001) # get() の戻り値は GeoJSON を表す Python の辞書(dict) # verbosity="geom" によりウェイに座標が付与され、LineString が得られる response = api.get(map_query, verbosity="geom")
- 取得した
responseオブジェクトを確認する。取得したデータは GeoJSON 形式 の辞書として返される。GeoJSON は地理情報データを表現する JSON ベースの標準フォーマットであり、多くの GIS ツールやライブラリで利用できる。
responseはすでに辞書なので、json.loads()などで再度パースする必要はない。print(type(response)) # <class 'dict'> print(response.keys()) # dict_keys(['type', 'features', ...]) print(len(response["features"])) # 取得した地物の数
- 取得したデータのタイプを指定して抽出する。
以下は、ライン(GeoJSON の
LineString)のうちhighwayタグを持つもの(道路データ)を抽出する例である。responseは辞書なので、["features"]で要素のリストにアクセスできる。# highway タグを持つラインのみを抽出 highways = [] for feature in response["features"]: if feature["geometry"]["type"] == "LineString": if "highway" in feature["properties"]: highways.append(feature) print(f"highway タグを持つラインの数: {len(highways)}") if highways: print(highways[0])結果が 0 件のとき:
highway タグを持つラインの数: 0と表示される場合は、次を確認する。(1) 手順1のapi.get(...)にverbosity="geom"を指定しているか(指定しないとウェイに座標が付かずLineStringにならない)。(2) バウンディングボックスの範囲内に道路が存在するか(建物や緑地だけの範囲では道路は得られない)。(3)response["features"]自体が空でないか(空であれば座標や User-Agent、ネットワークを確認する)。 - ラインのデータ構造を確認する。
ラインは複数のポイント(座標)で構成される。線分の場合は端点が2個、折れ線の場合は端点2個に加えて中間点が存在する。
# ラインのデータ構造を確認(最初の3つだけ表示) for i, highway in enumerate(highways[:3]): print(f"ライン {i+1}:") print(f" ID: {highway['id']}") print(f" タイプ: {highway['properties'].get('highway', '不明')}") print(f" 名前: {highway['properties'].get('name', '名前なし')}") coords = highway["geometry"]["coordinates"] print(f" ポイント数: {len(coords)}") print(f" 座標: {coords}") print()各出力は1個のラインを表す。
coordinatesには、ラインを構成する各ポイントの座標が格納されている。座標の順序について: GeoJSON の座標は [経度, 緯度] の順で格納される(一般的な「緯度, 経度」の順とは逆である)。
- ノード(ポイント)のデータ構造を確認する。
# ノード(ポイント)のデータを抽出 nodes = [] for feature in response["features"]: if feature["geometry"]["type"] == "Point": nodes.append(feature) print(f"ポイントの総数: {len(nodes)}") # 最初の3つだけ表示 for i, node in enumerate(nodes[:3]): print(f"ノード {i+1}:") print(f" ID: {node['id']}") print(f" 座標(経度, 緯度): {node['geometry']['coordinates']}") print(f" タグ: {node['properties']}") print()各出力は1個のポイントを表す。各ポイントは ID と座標を持つ。タグ(属性情報)は店舗や施設などには付与されるが、ウェイを構成する中間ノードでは空(
{})であることが多い。タグの付いた点だけを集めたい場合は、node["properties"]が空でないものを選別する。 - 取得したデータを geopandas で扱う(任意)。
GeoJSON は geopandas で直接読み込める。以下は、ライン(道路)データを GeoDataFrame に変換する例である。
import geopandas as gpd highway_geojson = {"type": "FeatureCollection", "features": highways} gdf = gpd.GeoDataFrame.from_features(highway_geojson, crs="EPSG:4326") print(gdf.head()) print(gdf.shape) # (行数, 列数)CRS について:
EPSG:4326の名目上の軸順は「緯度・経度」だが、GeoJSON の座標は「経度・緯度」で格納される。geopandas は GeoJSON 由来の座標を「経度・緯度」として読み込むため、from_featuresではこのEPSG:4326の指定でそのまま正しく扱える。GeoDataFrame に変換すると、属性での絞り込み、面積・距離の計算、地図への描画(
gdf.plot())などの空間分析が容易になる。
演習
本節の演習は、本文(手順1〜6)のコードを実行できる状態であることを前提とする。各演習のコードは、本文と同じ api オブジェクト(user_agent を指定して生成したもの)を使用する。
演習1.タグの付いた点(店舗)の取得
手順
- 本文手順1のコードを実行し、
api、lat、lonを準備する。 - 以下のコードを実行し、範囲内のコンビニ(
shop=convenience)のノードを取得して表示する。# 範囲内の shop=convenience のノードを取得(bbox は 南緯,西経,北緯,東経) query = f'node["shop"="convenience"]({lat-0.001},{lon-0.001},{lat+0.001},{lon+0.001})' shops = api.get(query) for feature in shops["features"]: print(feature["properties"].get("name", "名前なし"), feature["geometry"]["coordinates"]) "shop"="convenience"を"amenity"="restaurant"など別のタグに変更し、再度実行する。
ヒント
- タグ指定では
MapQueryではなく Overpass QL をget()に直接渡す。 - バウンディングボックスの順序は本文手順1と同じ(南緯, 西経, 北緯, 東経)である。
考察ポイント
- 取得された点の数は、範囲内に存在する該当施設の数と対応するか。
- タグを変更すると、取得される点の数や名前はどのように変わるか。
演習2.範囲の大きさと取得件数の関係
手順
- 本文手順1の
MapQueryの範囲(± 0.001)を± 0.002、± 0.005に変更し、それぞれverbosity="geom"を指定して取得する。 - 各範囲について、本文手順2の方法で
len(response["features"])を表示する。
ヒント
0.001度は緯度方向で約111m、経度方向は緯度によって変わる(本文手順1を参照)。- 範囲を広げるとリクエストの処理時間が長くなる。連続実行する場合は数秒の間隔を空ける。
考察ポイント
- 範囲を広げると取得件数はどのように変化するか。
- 件数の増え方は範囲の面積(辺の長さの2乗)に比例しているか。
まとめ
本記事で取得したデータの構造は以下のとおりである。
- ライン(ウェイ)データ: 複数のポイント座標で構成され、道路や河川などの線形要素を表す。GeoJSON 上は
LineStringとなる(ウェイに座標を付与するためverbosity="geom"を指定して取得する)。 - ポイント(ノード)データ: ID、座標(経度, 緯度)、タグ(属性情報)で構成される。GeoJSON 上は
Pointとなる。中間ノードではタグが空のことが多い。
取得したデータは response["features"] から辞書として直接扱えるほか、geopandas を使用して地図上への可視化や空間分析に利用できる。
参考: overpass パッケージは 0.8 系が安定版で、Python 3.10〜3.14 に対応する。開発拠点は Codeberg(codeberg.org/mvexel/overpass-api-python-wrapper)へ移行済みで、旧 GitHub リポジトリはアーカイブ化(読み取り専用)されている。バージョン 0.8.2 以降は user_agent の指定が必須となった。最新の情報やインストールは PyPI(https://pypi.org/project/overpass/) を参照する。次期 1.0 では OverpassClient など新 API の導入が予定されており、リリース後は記法が変わる点に留意する。