Pythonで郵便番号から住所を取得する②

IT

 お疲れさまです🍵 Yuinaです。

今回は、前回の記事でご紹介した

「Pythonで郵便番号から住所を取得する方法①」

の続きについてお話できればと思います。

前回は、MySQLに郵便局のデータを取り込む方法と、

PythonからMySQLへ接続して操作する手順をご紹介しました。(前回の投稿はこちら

 今回は、実際にPythonを使って郵便局のデータを取得・活用するスクリプトを作成していきます。

どうぞよろしくお願いいたします!

早速、処理を実装してみよう

 今回は、Pythonを使って「郵便番号から住所を取得する」処理を実装してみます。

以下のコードでは、MySQLに保存された郵便局データベースを使って、7桁の郵便番号から対応する住所を取得します。

実際のコードはこちらです👇

import mysql.connector

def get_address_by_zip(zip_code):
# 郵便番号の形式チェック
if len(zip_code) != 7 or not zip_code.isdigit():
return "郵便番号は7桁の数字で入力してください。"

try:
# データベースに接続
conn = mysql.connector.connect(
host='XXXXX',
user='XXXX',
password='XXXX',
database='XXX',
connection_timeout=5
)
cursor = conn.cursor()

# 郵便番号に一致する住所を検索
query = """
SELECT kana1, kana2, kana3, name1, name2, name3
FROM post
WHERE post_code = %s
"""
cursor.execute(query, (zip_code,))
results = cursor.fetchall()

if results:
# かな・漢字の住所を結合して表示
kana = " ".join([part if part is not None else "" for part in results[0][:3]])
name = " ".join([part if part is not None else "" for part in results[0][3:]])
return f"住所(かな): {kana.strip()}\n住所(漢字): {name.strip()}"
else:
return "該当する住所が見つかりませんでした。"

except mysql.connector.Error as err:
return f"データベースエラー: {err}"

finally:
# リソースの後始末
if 'cursor' in locals():
cursor.close()
if 'conn' in locals():
conn.close()

# ユーザーから郵便番号を受け取って検索
zip_code = input("郵便番号(7桁)を入力してください: ").strip()
address = get_address_by_zip(zip_code)
print(address)

もう少し詳しく解説していきます。

if len(zip_code) != 7 or not zip_code.isdigit():
return "郵便番号は7桁の数字で入力してください。"

この関数は、ユーザーが入力した郵便番号をもとに、対応する住所をデータベースから取得するためのものです。
まず、最初に行っているのが「入力された郵便番号の形式チェック」です。

🔍 ここでやっていること:

len(zip_code) != 7は、郵便番号が7文字じゃない場合はアウトです。日本の郵便番号は7桁なのでこのチェックが必要になります。

not zip_code.isdigit()は、郵便番号に数字以外の文字が含まれていた場合もエラーにします。たとえば「160-0011」や「abc1234」などがこれに当たります。

try:
# データベースに接続
conn = mysql.connector.connect(
host='XXXXX',
user='XXXX',
password='XXXX',
database='XXX',
connection_timeout=5
)

続いて、データベースとMYSQLを接続します。

🔍 ここでやっていること:

mysql.connector.connect() は、Python から MySQL データベースへ接続するための関数です。

try: の中に書いてあるのは、接続時に何かトラブルが起きても、エラーとしてキャッチできるようにしているためです。

各パラメータの意味:

  • host='XXXXX'
    → データベースが動いているサーバーのアドレスです。
  • user='XXXX'
    ログインユーザー名です。
  • password='XXXX'
    → ユーザー名に対応するパスワードです。
  • database='XXX'
    → 接続したいデータベース名です。郵便番号データを格納しているデータベース名をここに入れます。
  • connection_timeout=5
    → 接続にかかる待ち時間です。5秒以内に接続できなければタイムアウトしてエラーになります。

この接続がうまくいけば、次の処理でデータベースから郵便番号を使って、住所データを検索することができます。

逆に、サーバーが落ちていたり、パスワードが間違っていたりすると、この時点でエラーになります。そのときは後の except ブロックでエラー処理が行われるようになっているんですね。

cursor = conn.cursor()

ここでは、カーソルの作成をしています。

🔍 ここでやっていること:

cursor は、データベースとやりとりを行うためのものです。これを使って、SQL文(今回ならSELECT文)を実行したり、実行結果を受け取ったりします。

イメージとしてはconn は「データベースへの入り口で、cursor は「その中でデータを操作するための手」みたいな感じです。

# 郵便番号に一致する住所を検索
query = """
SELECT kana1, kana2, kana3, name1, name2, name3
FROM post
WHERE post_code = %s
"""

ここでは、郵便番号に一致する住所を検索するSQLが書かれています。

🔍 ここでやっていること:

これは、MySQLに送るSELECT文を準備している部分です。
SQL文自体は、Pythonの中で
文字列として書かれています。

各部分の意味:

  • SELECT kana1, kana2, kana3, name1, name2, name3
    → 欲しいカラム(列)を指定しています。
    • kana1, kana2, kana3 は「住所のかな表記」
    • name1, name2, name3 は「住所の漢字表記」
      例えば:都道府県/市区町村/町名のように分かれているイメージです。
  • FROM post
    post という名前のテーブルからデータを取ってきます。
    これは郵便局のデータが入っているテーブルだと考えられます。
  • WHERE post_code = %s
    → これは検索条件です。
    post_code(郵便番号)が指定された値(後で渡す値)と一致するデータだけを取得します。

%s プレースホルダー(仮の場所)です。
SQLインジェクションという悪意のあるデータによる攻撃を防ぐために、
値をあとで別で渡すようにして、SQL文と値を分離して安全に実行します。

cursor.execute(query, (zip_code,))
results = cursor.fetchall()

ここでは、SQL文の実行と結果の取得します。

🔍ここでやっていること:

1.SQL文を実行する

cursor.execute(query, (zip_code,))は、

queryに書いたSQL文をMySQLに送って実行しています。

(zip_code,)%s に当てはめる値。タプル形式で渡す必要があるのでカンマ付き。

ここで実行されるのは例えばこんなSQL:

SELECT kana1, kana2, kana3, name1, name2, name3
FROM post
WHERE post_code = '1600022'

2.検索結果を全部まとめて取得

results = cursor.fetchall()は、検索結果が複数行あったときのために、全部まとめて取り出しています。

results はリスト形式で、中身はタプルの集まりです。 たとえばこんな感じになります:

[('トウキョウト', 'シンジュクク', 'シンジュク', '東京都', '新宿区', '新宿')]

ちなみにタプル(tuple)とはPythonにおける「複数の値をまとめて持てるデータ型」のひとつです。

郵便番号で住所を取り出したときのこの行:

('トウキョウト', 'シンジュクク', 'シンジュク', '東京都', '新宿区', '新宿')

これも1つのタプルです。
イメージとしては、1行分の住所データが1つのタプルにまとめられてる感じでしょうか。

if results:
# かな・漢字の住所を結合して表示
kana = " ".join([part if part is not None else "" for part in results[0][:3]])
name = " ".join([part if part is not None else "" for part in results[0][3:]])
return f"住所(かな): {kana.strip()}\n住所(漢字): {name.strip()}"
else:
return "該当する住所が見つかりませんでした。"

ここは検索結果があったかどうかを判定して、住所をきれいに整えて返す部分です。

if resultus には、データベースから取得した検索結果がリストの形で入っています。
この条件文では、検索結果が「存在するかどうか」をチェックしています。

データが存在すれば 、ifブロックが実行され、検索にヒットしなかった場合はelseに進みます。

results[0] には、タプル形式で以下のような値が入っているとします:

('トウキョウト', 'シンジュクク', 'シンジュク', '東京都', '新宿区', '新宿')

これをそれぞれ、かなの住所と漢字の住所に分けて整形します。

kana = " ".join([part if part is not None else "" for part in results[0][:3]])
name = " ".join([part if part is not None else "" for part in results[0][3:]])

[:3] で最初の3つ(かな)を、[3:] で後ろの3つ(漢字)を取り出しています。

None の場合は空文字 "" に置き換えて、エラーにならないようにしています。

" ".join(...) で、それらのパーツをスペースでつなげています。

return f"住所(かな): {kana.strip()}\n住所(漢字): {name.strip()}"

こちらは、住所をひらがなと漢字でフォーマットして返す部分ですね。

そして、次の部分:

else:
return "該当する住所が見つかりませんでした。"

これは、もし該当する住所が見つからなかった場合に「該当する住所が見つかりませんでした。」というメッセージを返す処理です。

except mysql.connector.Error as err:
return f"データベースエラー: {err}"

この部分は、MySQLの接続中にエラーが発生した場合にエラーをキャッチし、そのエラーメッセージをf-stringを使ってユーザーに返しています。

return f"データベースエラー: {err}"

これにより、MySQLのエラーが発生した際に、エラーメッセージの内容が表示されます。

pythonコピーする編集するfinally:
# リソースの後始末
if 'cursor' in locals():
cursor.close()
if 'conn' in locals():
conn.close()

finallyブロックは、tryブロックとexceptブロックの後に必ず実行される部分で、

リソースの掃除や不要なデータの削除を行います。

cursor.close()はデータベース操作を終了した後、cursorを閉じます。

conn.close()conn(データベース接続)を閉じて、リソースを解放します。

if 'cursor' in locals()if 'conn' in locals() は、それぞれcursorconnが定義されている場合にのみ閉じる処理を行うことで、未定義の変数に対してエラーが発生しないようにしています。

zip_code = input("郵便番号(7桁)を入力してください: ").strip()

この部分はユーザーに郵便番号を入力してもらい、入力された内容を整えて変数 zip_code に格納します。

input()はユーザーからの入力を受け取る関数です。

.strip() は文字列の先頭と末尾の余分な空白文字を取り除くメソッドです。

入力に余計なスペースが含まれていた場合に、そのスペースを削除してきれいにします。

address = get_address_by_zip(zip_code)
print(address)

ここでは、郵便番号に基づいて住所を取得します。

get_address_by_zip(zip_code)では、関数 get_address_by_zip() を呼び出しています。

引数として、先ほど取得した郵便番号 zip_code を渡しています。

get_address_by_zip() が返す住所の結果は、変数 address に格納されます。

この後、print(address)で、変数addressに格納された住所を表示します。

まとめ

今回は、PythonとMySQLを使って、郵便番号から住所を検索するシンプルなスクリプトを作成しました。

このようなスクリプトは、業務システムの一部や個人ツールとしても活用できます。
ぜひ、自分の環境に合わせて応用してみてください!

コメント

タイトルとURLをコピーしました