Skip to content

xROAD-API 77条関連 橋梁点検報告書取得

全国道路施設点検データベース(xROAD)から橋梁の第77条点検表記録様式ファイルを取得するガイドです。

クイックスタート

# 1. 橋梁を検索して座標IDを取得
GET /xROAD/api/v1/bridges?name=橋梁名
 レスポンス: shisetsu_id = "43.03892,141.35859"  # 座標形式(重要!)

# 2. 点検報告書をダウンロード
GET /xROAD/api/v1/bridges/report77/{座標ID}/{年度}
 Excelファイルがダウンロードされる

⚠️ 重要: BR形式のID(BR0-011002-00001)ではなく、座標形式のIDを使用すること

1. 橋梁を検索して座標IDを取得

import requests
import urllib.parse

class XROADClient:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = "https://road-structures-db-bridge.mlit.go.jp/xROAD/api/v1"
        self.headers = {"API-key": self.api_key}

    def search_bridge(self, name: str):
        """橋梁を検索して座標IDを取得"""
        response = requests.get(
            f"{self.base_url}/bridges",
            headers=self.headers,
            params={"name": name, "limit": 10},
            timeout=60
        )
        data = response.json()

        facilities = []
        for item in data.get('result', []):
            facilities.append({
                'coord_id': item.get('shisetsu_id'),  # 座標形式ID
                'br_id': item.get('shisetsu_bangou'),  # BR形式ID(参考)
                'name': item.get('syogen', {}).get('shisetsu', {}).get('meisyou', '')
            })
        return facilities

2. 点検報告書をダウンロード

    def download_report77(self, coord_id: str, year: int):
        """第77条点検表をダウンロード"""
        url = f"{self.base_url}/bridges/report77/{coord_id}/{year}"

        response = requests.get(url, headers=self.headers, stream=True, timeout=60)

        if response.status_code == 200:
            # ファイル名をContent-Dispositionから取得
            cd = response.headers.get('Content-Disposition', '')
            if "filename*=UTF-8''" in cd:
                encoded = cd.split("filename*=UTF-8''")[1].split(';')[0]
                filename = urllib.parse.unquote(encoded)
            else:
                filename = f"点検報告書_{year}.xlsx"

            # ファイル保存
            with open(filename, 'wb') as f:
                for chunk in response.iter_content(chunk_size=8192):
                    f.write(chunk)

            return filename
        elif response.status_code == 400:
            print(f"データなし({year}年)")
        return None

実装例

ファイル名をContent-Dispositionから取得

cd = response.headers.get('Content-Disposition', '')
if "filename*=UTF-8''" in cd:
    encoded = cd.split("filename*=UTF-8''")[1].split(';')[0]
    filename = urllib.parse.unquote(encoded)
else:
    filename = f"点検報告書_{year}.xlsx"

ファイル保存

with open(filename, 'wb') as f:
    for chunk in response.iter_content(chunk_size=8192):
        f.write(chunk)

使用例

# 使用例
client = XROADClient("YOUR_API_KEY")
facilities = client.search_bridge("幌平橋")
if facilities:
    coord_id = facilities[0]['coord_id']
    client.download_report77(coord_id, 2024)

API仕様

施設データ簡易参照API(GET)

GET /xROAD/api/v1/bridges?name={橋梁名}
  • name: 橋梁名(部分一致)
  • limit: 取得件数(デフォルト: 100)
  • レスポンス: shisetsu_id(座標形式)、shisetsu_bangou(BR形式)

第77条点検表記録様式ファイル取得API

GET /xROAD/api/v1/bridges/report77/{座標ID}/{年度}
  • 座標ID: 緯度,経度形式(例: 43.03892,141.35859
  • 年度: 西暦4桁
  • レスポンス: Excelファイル(.xlsx)またはZIPファイル

トラブルシューティング

問題 原因 解決方法
HTTP 400 データなしまたはID形式エラー 座標形式IDを使用、別年度を試行
HTTP 401 APIキー認証エラー ヘッダー名 API-key を確認
タイムアウト API応答が遅い timeout=60以上に設定
2024年ファイル取得失敗 otherFile APIを使用している report77 APIを使用する

成功実績

幌平橋(車)の点検報告書ダウンロード成功例: - 2024年: 幌平橋通線_幌平橋(車)(上下線一体).xlsx (3.9MB) - 2019年: 幌平橋通線_幌平橋(車).xlsx (1.4MB) - 2015年: 市道幌平橋通線_幌平橋(車).xlsx (673KB)

重要な注意点

✅ 正しい方法

  • API: /bridges/report77/{座標ID}/{年度}
  • ID形式: 座標形式(43.03892,141.35859
  • 必要情報: 座標IDと年度のみ

❌ 間違った方法

  • API: /bridges/otherFile/{file_id}
  • ID形式: BR形式(BR0-011002-00001
  • 問題点: ファイルIDの構築が必要、2024年ファイルアクセス不可

その他のAPI

高度検索API(詳細検索が必要な場合)

POST /xROAD/api/v1/bridges/search
{
  "querys": [{
    "key": "syogen.shisetsu.meisyou",
    "value": "橋梁名",
    "op": 7  // 部分一致
  }],
  "limit": 100
}

なぜ高度検索APIだけではダメなのか

高度検索APIはtenken.kiroku.file_meiでファイル名を返すが: 1. ファイルIDが分からない - otherFile APIに必要なIDが不明 2. 付属ファイルリストAPIに未登録 - 幌平橋のファイルは登録されていない 3. report77 APIなら直接ダウンロード可能 - 座標IDと年度だけでOK

方法 必要な情報 2024年ファイル
otherFile API ファイルID(不明) ❌ 失敗
report77 API 座標ID + 年度 ✅ 成功

既知の問題(バグレポート)

otherFileList APIのフィルタリング不具合

問題: 付属ファイルリスト取得API (/bridges/otherFileList) で施設IDによるフィルタリングが機能しない

再現方法:

# どの施設IDを指定しても同じ16,236件が返される
GET /bridges/otherFileList?shisetsu=43.03892,141.35859  # 幌平橋(車) 結果: 16,236件(全件)

GET /bridges/otherFileList?shisetsu=99.99999,99.99999  # 存在しない座標 結果: 16,236件(全件)※同じ結果

期待される動作: 指定施設のファイルのみ返却 実際の動作: 全件(16,236件)が返却される

影響: - 幌平橋のファイルが取得できない(0件として扱われる) - クライアント側での全件フィルタリングが必要

回避策: report77 APIを使用する(正常動作)

デバッグ用curlコマンドセット

#!/bin/bash
# otherFileList API バグ検証スクリプト

API_KEY="X9IP3rLyofzHJaiK02dw7GXZbYoyTpQRE68R69Lr"
BASE_URL="https://road-structures-db-bridge.mlit.go.jp/xROAD/api/v1"

echo "=== Testing otherFileList API with different facility IDs ==="

# テスト1: 幌平橋(車)の座標ID
echo -e "\n1. Testing with 幌平橋(車) coordinate ID (43.03892,141.35859):"
curl -s -X GET "${BASE_URL}/bridges/otherFileList?shisetsu_id=43.03892,141.35859&limit=1" \
  -H "API-key: ${API_KEY}" | jq '{count: .resultset.count, first_file: .result[0].file_name}'

# テスト2: 幌平橋の座標ID  
echo -e "\n2. Testing with 幌平橋 coordinate ID (44.30767,141.90496):"
curl -s -X GET "${BASE_URL}/bridges/otherFileList?shisetsu_id=44.30767,141.90496&limit=1" \
  -H "API-key: ${API_KEY}" | jq '{count: .resultset.count, first_file: .result[0].file_name}'

# テスト3: 幌平橋(歩)の座標ID
echo -e "\n3. Testing with 幌平橋(歩) coordinate ID (43.03906,141.35871):"
curl -s -X GET "${BASE_URL}/bridges/otherFileList?shisetsu_id=43.03906,141.35871&limit=1" \
  -H "API-key: ${API_KEY}" | jq '{count: .resultset.count, first_file: .result[0].file_name}'

# テスト4: 存在しない座標ID
echo -e "\n4. Testing with non-existent coordinate ID (99.99999,99.99999):"
curl -s -X GET "${BASE_URL}/bridges/otherFileList?shisetsu_id=99.99999,99.99999&limit=1" \
  -H "API-key: ${API_KEY}" | jq '{count: .resultset.count, first_file: .result[0].file_name}'

# テスト5: パラメータ名 shisetsu で試す
echo -e "\n5. Testing with parameter name 'shisetsu' (43.03892,141.35859):"
curl -s -X GET "${BASE_URL}/bridges/otherFileList?shisetsu=43.03892,141.35859&limit=1" \
  -H "API-key: ${API_KEY}" | jq '{count: .resultset.count, first_file: .result[0].file_name}'

echo -e "\n=== Analysis ==="
echo "If all tests return the same count (16236), the filtering is not working."
echo "Expected: Different facilities should return different file counts."

実行結果例(2024年8月28日):

1. Testing with 幌平橋(車) coordinate ID:
{
  "count": 16236,
  "first_file": "砥山簾舞川沿西線_砥山橋.xlsx"
}

2. Testing with 幌平橋 coordinate ID:
{
  "count": 16236,
  "first_file": "砥山簾舞川沿西線_砥山橋.xlsx"
}

3. Testing with non-existent coordinate ID:
{
  "count": 16236,
  "first_file": "砥山簾舞川沿西線_砥山橋.xlsx"
}

すべて同じ結果(16,236件)が返される = フィルタリングが機能していない