行動変容アプリのコーディング編を書いていく。⇒ 前回の記事はこちら
目次
1.UIの作成
2.APIリクエストの作成
3.ディレクトリ構造の確認
4.次回(デプロイ編)
1.UIの作成
まず初めにUIについて考える。
UIとは、画面のボタンや文字などの操作部分であり、ユーザーが直感的に使いやすいものである必要がある。
不動産取引情報にAPIリクエストを送るために、以下のデータをユーザーから入力が必要。
【必要なユーザー入力】
・都道府県名
・市町村名
・検索したい取引年度
上記の3つのユーザー入力に必要な入力フィールドと、検索ボタンを1つ設置したシンプルなUIを考える。
import streamlit as st
from src.send_api import connect_api
from src.pref_data import pref_id, change_index
# フッターのHTMLとCSS
footer = """
<style>
.footer {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
background-color: #f1f1f1;
color: black;
text-align: center;
padding: 10px;
}
</style>
<div class="footer">
<p>不動産価格(取引価格・成約価格)情報取得API(国土交通省)を基に、作成しています。</p>
</div>
"""
# フッターを挿入
st.markdown(footer, unsafe_allow_html=True)
# 画面に表示するアプリ名
st.title("不動産取引情報検索")
# 3つのユーザー入力用フィールドを設置(カラムで横並びに設定)
input_col1, input_col2, input_col3 = st.columns(3)
with input_col1:
prefecture = st.selectbox(
label="都道府県", options=[index for index, i in pref_id.items()]
) # pref_idについては、後ほど実装
with input_col2:
city = st.text_input(label="市町村(空白可)", placeholder="大阪市")
with input_col3:
year = st.number_input(label="取引時期(西暦)", value=2024, step=0)
# 検索ボタンを設置(connect_api関数は後ほど実装)
search = connect_api(api_key, prefecture, city, year) if st.button("検索") else None
2.APIリクエストの作成
前項のコードでは未定義のもの
pref_id
connect_api関数
【pref_idについて】
都道府県については47個しかないため、予めpref_idとしてpref_data.pyに辞書型データとして格納しておき、モジュールとして呼び出す仕様とした。
pref_id = {
"北海道": "01",
"青森県": "02",
"岩手県": "03",
"宮城県": "04",
"秋田県": "05",
"山形県": "06",
"福島県": "07",
"茨城県": "08",
"栃木県": "09",
"群馬県": "10",
"埼玉県": "11",
"千葉県": "12",
"東京都": "13",
"神奈川県": "14",
"新潟県": "15",
"富山県": "16",
"石川県": "17",
"福井県": "18",
"山梨県": "19",
"長野県": "20",
"岐阜県": "21",
"静岡県": "22",
"愛知県": "23",
"三重県": "24",
"滋賀県": "25",
"京都府": "26",
"大阪府": "27",
"兵庫県": "28",
"奈良県": "29",
"和歌山県": "30",
"鳥取県": "31",
"島根県": "32",
"岡山県": "33",
"広島県": "34",
"山口県": "35",
"徳島県": "36",
"香川県": "37",
"愛媛県": "38",
"高知県": "39",
"福岡県": "40",
"佐賀県": "41",
"長崎県": "42",
"熊本県": "43",
"大分県": "44",
"宮崎県": "45",
"鹿児島県": "46",
"沖縄県": "47",
}
【connect_api関数について】
都道府県についてはデータ数が少ないため、予めデータとして準備するのも手間ではないが、各都道府県の市町村コードを全て調べてデータ化するのは少し骨が折れる。
調べたところ、市町村コードを取得できるAPIが予め用意してあるため、APIリクエストする際に、ユーザーが入力した市町村コードを取得する仕様とした。
⇒ 都道府県内市区町村一覧取得API
# APIによるデータ取得
# インポート
import streamlit as st
import requests
import pandas as pd
from src.pref_data import pref_id
# API接続関数
def connect_api(api_key: str | int, prefecture: str, city: str | None, year: int):
api_key = api_key
url = "https://www.reinfolib.mlit.go.jp/ex-api/external/XIT002"
headers = {"Ocp-Apim-Subscription-Key": f"{api_key}"}
params = {"year": year, "area": pref_id[prefecture]}
response = requests.get(url, headers=headers, params=params)
json_data = response.json()
# 市町村コードの取得
def send_city_id(json_data, city: str | None):
try:
for item in json_data["data"]:
if item["name"] == city:
return item["id"]
if city == "":
return None
else:
return "該当する市町村が存在しません"
except KeyError:
return "該当する市町村が存在しません"
# 入力された市町村が存在しない場合
city_id = send_city_id(json_data, city)
url = "https://www.reinfolib.mlit.go.jp/ex-api/external/XIT001"
params["city"] = city_id
response = requests.get(url, headers=headers, params=params)
json_data = response.json()
# 検索結果に応じた内容を画面描画
try:
df = pd.DataFrame(json_data["data"])
df["TradePrice"] = df["TradePrice"].apply(lambda x: f"¥{int(x):,}")
df = df.drop(
columns=[
"PriceCategory",
"Prefecture",
"MunicipalityCode",
"UnitPrice",
"Frontage",
"PricePerUnit",
]
)
df = df.rename(columns=change_index)
df.rename(
columns={"用途地区": "取引価格", "取引価格": "用途地区"}, inplace=True
)
df["取引価格"], df["用途地区"] = df["用途地区"], df["取引価格"]
st.link_button("空き家を登録してみる(外部サイト)", url=my_url)
st.write(f"{year}年の{prefecture}{city}の取引情報")
st.write(f"取引件数{str(len(df))}件")
st.dataframe(df)
except KeyError:
st.write("該当する市町村が存在しません")
上記のコードでは未定義のもの
change_index
api_key
【change_indexについて】
APIリクエストで取得したデータが英語のため、和訳して表示することを考える。
データ数は20データ程しかないため、都道府県データと同じように、pref_data.pyに辞書型データとして格納し、change_indexモジュールとして呼び出す仕様とした。
# 下記を追記
change_index = {
"PriceCategory": "情報種別",
"Type": "取引種別",
"Region": "用途地区",
"Municipality": "市町村",
"DistrictName": "地名",
"TradePrice": "取引価格",
"FloorPlan": "間取り",
"Area": "面積(㎡)",
"LandShape": "土地の形状",
"TotalFloorArea": "延床面積(㎡)",
"BuildingYear": "建築年",
"Structure": "建物構造",
"Use": "建物用途",
"Purpose": "取引後の利用用途",
"Direction": "前面道路の方位",
"Classification": "前面道路の種類",
"Breadth": "前面道路の幅員(m)",
"CityPlanning": "都市計画区域",
"CoverageRatio": "建蔽率(%)",
"FloorAreaRatio": "容積率(%)",
"Period": "取引時期",
"Renovation": "リノベの有無",
"Remarks": "備考"
}
【api_key】
connect_api関数にAPIキーを渡す必要があるが、大変機微な情報であるため、ハードコーディングはできない。
そのため秘匿化処理を含めて、次回のデプロイ編で解説する。
3.ディレクトリ構造の確認
現在のディレクトリ構造を確認してみる。
_ init _.pyについては ⇒ Python init.pyってなに?
my_project/
│
├── main.py
├── __init__.py
│
├── src/
│ ├── __init__.py
│ ├── pref_data.py
│ ├── send_api.py
│
4.次回(デプロイ編)
次回、Streamlitクラウドへデプロイした話を書く予定。