Python の overpass を用いて OpenStreetMap のデータをダウンロード

概要

Python の overpass パッケージを使用して、OpenStreetMap から地図データをダウンロードする方法を解説する。Google Map で緯度経度を調べ、Overpass API を通じてポイント(ノード)やライン(ウェイ)のデータを取得し、GeoJSON 形式で処理する手順を示す。

その他情報

本記事では MapQuery を用いて、指定範囲内のウェイ(線)と、それを構成するノード(点)をまとめて取得する。OpenStreetMap の3種類の要素は、取得後の GeoJSON では次のように表現される。

MapQuery で返る Point の多くは、ウェイを構成する中間ノードであり、タグ(属性)を持たない(properties が空 {} の)ものが多い。店舗や施設のように「タグの付いた点」だけが欲しい場合は、演習で扱うタグ指定のクエリを使う。

前提知識: Python の基本的な操作(変数、リスト、辞書、for 文など)を理解していることを前提とする。本記事のプログラムは Windows 上で動作し、GPU は不要である(CPU のみで動作する)。

利用上の注意: Overpass API には利用制限がある。短時間に大量のリクエストを送信すると、一時的にアクセスが制限される。制限に達すると HTTP エラーや例外が発生するため、連続して実行する場合は数秒の間隔を空ける。また、公開サーバーへのリクエストには User-Agent の指定が必須である(指定しないとアクセスがブロックされる場合がある)。User-Agent は実在のメールアドレスである必要はないが、サーバー運用者が問題発生時に判別できるよう、アプリケーション名と連絡可能な識別子を記載する。OpenStreetMap のデータは Open Database License (ODbL) の下で提供されており、利用時にはライセンス条件に従う。

目次

関連する外部ページ

実行環境の準備

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:インストーラーによるインストール

  1. Python公式サイト(https://www.python.org/downloads/)にアクセスし、「Download Python 3.x.x」ボタンからWindows用インストーラーをダウンロードする。
  2. ダウンロードしたインストーラーを実行する。
  3. 初期画面の下部に表示される「Add python.exe to PATH」にチェックを入れてから「Customize installation」を選択する。このチェックを入れ忘れると、コマンドプロンプトから python コマンドを実行できない。
  4. 「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 プログラムを解釈・実行するソフトウェア)を選択する必要がある.

  1. コマンドパレット(コマンド名で機能を呼び出す VS Code の入力欄)を開く(Ctrl+Shift+P
  2. Python: Select Interpreter と入力する
  3. 表示される一覧から,使用する Python(例:C:\Program Files\Python312\python.exe)を選択する.

Python プログラム実行手順

[Windows での Python プログラム実行手順を見るには、ここをクリック]

Windows での Python 実行手順(Visual Studio Codeを使用)

プログラムファイルの作成と保存

  1. 左サイドバーの「エクスプローラー」アイコン(Ctrl+Shift+E)をクリックする
  2. 「NO FOLDER OPENED」(作業対象フォルダが未選択の状態)と表示される場合は,「Open Folder」をクリックし,プログラムを保存するフォルダを選択する

    続いて「フォルダを信用するか」を確認する画面(フォルダ内のコードを実行してよいか確認する VS Code の仕組み)が表示されるので,チェックして Yes を選択する

  3. フォルダ名の右側に表示される「新しいファイル」アイコンをクリックする
  4. ファイル名(例:aitask.py.ファイル名は何でも良い)を入力し Enter を押す.拡張子は .py(Python ファイルを示す拡張子)とする
  5. 実行したいコードを選択し,Ctrl+C でコピーする.VS Code のエディタ領域に Ctrl+V で貼り付ける
  6. Ctrl+S で保存する

プログラムの実行

  1. エディタ右上の三角形「▷」アイコン(Run Python File:現在開いている Python ファイルを実行するボタン)をクリックする.または,エディタ上で右クリックし「ターミナルで Python ファイルを実行」を選択する
  2. VS Code 下部のターミナル(コマンドの入出力を表示する画面)に,実行結果(print 関数の出力等)が表示される
  3. tkinter(Python 標準の GUI ライブラリ)のファイル選択ダイアログを使うプログラムを実行した場合は,ダイアログが開くので対象画像を選択する
  4. VS Code 下部のターミナルで実行結果を確認する.OpenCV ウィンドウ(OpenCV が画像を表示するために開く専用ウィンドウ)が開いた場合はそちらも確認する.OpenCV ウィンドウは,マウスクリックでウィンドウをアクティブ(操作対象の状態)にしてからキーを押すと終了する

必要な Python ライブラリのインストール(Windows 上)

本記事で使用するライブラリは、Windows 用のビルド済みパッケージ(wheel)が配布されている。そのため C/C++ コンパイラのインストールは不要であり、pip install のみでインストールできる。

  1. 管理者権限コマンドプロンプトを起動する (手順:Windowsキーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。
  2. 以下のコマンドを実行し、必要なライブラリをインストールする。
    pip install -U --no-user overpass
    pip install -U --no-user geopandas

overpass は Overpass API からデータを取得するライブラリ、geopandas は取得した地理空間データを表形式で扱い、可視化や空間分析を行うライブラリである。

Google Map を用いて緯度経度を調べる

OpenStreetMap からデータをダウンロードするには、対象地域の緯度経度の指定が必要である。ここでは Google Map を使用して座標を取得する。

  1. Google Map を開く。

    https://www.google.co.jp/maps

  2. Google Map で任意の場所に移動する。
    Google Map の画面
  3. 目的の場所で右クリックし、表示されたメニューの先頭にある緯度・経度の数値をクリックする(クリックするとクリップボードにコピーされる)。
    Google Map で右クリックメニューを表示した画面
  4. 緯度と経度の値を記録しておく。値は「緯度, 経度」の順で表示される。
    Google Map で緯度経度が表示された画面

Python を用いて OpenStreetMap のデータをダウンロードして処理する

Python プログラムの実行方法

Windows では、コマンドプロンプトで python ファイル名.py を実行するか、対話モード(python と入力して起動)に1行ずつ貼り付けて実行する。

OpenStreetMap のデータ構造: OpenStreetMap のデータは、ノード(点)、ウェイ(線)、リレーション(複数要素の組み合わせ)の3種類で構成される。ノードは緯度経度を持つ点で、店舗や交差点などを表す。ウェイは複数のノードを順に結んだ線で、道路や河川などを表す。各要素には タグ(キーと値のペア)が付与され、要素の種類や属性を示す(例:道路には highway=primary のようなタグが付く)。

  1. ダウンロードしたい地図の緯度と経度を設定し、データを取得する。

    以下の 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")
    
    Python で overpass を使用したコードの実行画面
  2. 取得した response オブジェクトを確認する。

    取得したデータは GeoJSON 形式 の辞書として返される。GeoJSON は地理情報データを表現する JSON ベースの標準フォーマットであり、多くの GIS ツールやライブラリで利用できる。response はすでに辞書なので、json.loads() などで再度パースする必要はない。

    print(type(response))             # <class 'dict'>
    print(response.keys())            # dict_keys(['type', 'features', ...])
    print(len(response["features"]))  # 取得した地物の数
    
    response オブジェクトの出力結果
  3. 取得したデータのタイプを指定して抽出する。

    以下は、ライン(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、ネットワークを確認する)。

  4. ラインのデータ構造を確認する。

    ラインは複数のポイント(座標)で構成される。線分の場合は端点が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 の座標は [経度, 緯度] の順で格納される(一般的な「緯度, 経度」の順とは逆である)。

  5. ノード(ポイント)のデータ構造を確認する。
    # ノード(ポイント)のデータを抽出
    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"] が空でないものを選別する。

  6. 取得したデータを 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. 本文手順1のコードを実行し、apilatlon を準備する。
  2. 以下のコードを実行し、範囲内のコンビニ(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"])
    
  3. "shop"="convenience""amenity"="restaurant" など別のタグに変更し、再度実行する。

ヒント

考察ポイント

演習2.範囲の大きさと取得件数の関係

手順

  1. 本文手順1の MapQuery の範囲(± 0.001)を ± 0.002± 0.005 に変更し、それぞれ verbosity="geom" を指定して取得する。
  2. 各範囲について、本文手順2の方法で len(response["features"]) を表示する。

ヒント

考察ポイント

まとめ

本記事で取得したデータの構造は以下のとおりである。

取得したデータは 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 の導入が予定されており、リリース後は記法が変わる点に留意する。