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件)が返される = フィルタリングが機能していない