日本郵便で公開されている郵便番号データをデータベースのSQLiteで利用しようと思い、CSVファイルをダウンロード。京都の住所は通り名の有り無しなど、同じ郵便番号でも複数の住所表記の仕方があるので、CSVでどのように処理されているか京都の郵便番号データで確認してみます。すると、このCSVをそのまま使える人はいるのか?っていうぐらい、面倒なデータだということがわかりました。そこで、使いやすいようにpythonでデータを整形することにします。
日本郵便 郵便番号データダウンロードはこちら
もくじ
CSVファイルを分析
同じ郵便番号なのに町名が複数行に分割

同じ郵便番号なのに町域名(漢字)が複数行に分割されています。町域名(漢字)以外の項目はすべて同じです。しかも、複数行に分ける区切り方がよくわかりません。
通り名にフリガナの有無と複数行に分割

町域名の通り名にフリガナが有るのと無いのがあります。しかも、複数行に分割してあります。法則が全くわかりません。
郵便番号データファイルの形式等
法則性がよくわからないので、日本郵便のホームページで確認します。

全角となっている町域部分の文字数が38文字を越える場合、また半角となっているフリガナ部分の文字数が76文字を越える場合は、複数レコードに分割しています。
どうやら文字制限が全角38文字のようです。
他の町域名データ見てみると、どうやら10番目の項目が1のときに、町域名の()部分にフリガナがつけられるらしい、ということがわかりました。しかし、10番目の項目は必要ないので出来れば取り込みたくありません。そこで、「、()」の有無で条件分岐する方法を考えてみました。
pythonでCSVデータを整形

同じ郵便番号の町域名(漢字)を1つに結合できました。

フリガナも1つに結合。これで何とか使えそうです。
抽出したデータ項目
- 郵便番号 7桁 …… 半角数字
- 都道府県名 ………… 半角カタカナ(コード順に掲載)
- 市区町村名 ………… 半角カタカナ(コード順に掲載)
- 町域名 ……………… 半角カタカナ(五十音順に掲載)
- 都道府県名 ………… 漢字(コード順に掲載)
- 市区町村名 ………… 漢字(コード順に掲載)
- 町域名 ……………… 漢字(五十音順に掲載)
整形したCSVデータ
使用・再配布・移植・改良について
出典:日本郵便
郵便番号データに限っては日本郵便株式会社は著作権を主張しません。自由に配布していただいて結構です。
らしいので、自分で使う用に整形したCSVファイルを置いておきます。京都の郵便番号データが欲しかっただけなので、すべてのデータが綺麗に整形出来ているかは確認していません。
→少しだけチェックしてみました。
京都の郵便番号データ (CSV)
全国の郵便番号データ (CSV)
ソースコード (python)
複数行に分割されている、町域名(漢字)を結合したいので、「、()」の有無で条件分岐しています。郵便番号が1つ前と同じで、()の片方が残っている場合、町域名を結合しています。
import csv
# 空のリストを作成
zip_data = []
# 全国一括の郵便番号のCSVファイルを開いて読込
with open('KEN_ALL.CSV', 'rt', encoding='Shift-JIS') as f:
reader = csv.reader(f)
# 必要な項目を取出して、1行ずつリストに書込
for row in reader:
zcode = row[2] # 郵便番号
kana_ken = row[3] # 都道府県名(半角カタカナ)
kana_shi = row[4] # 市町村名(半角カタカナ)
kana_cho = row[5] # 町域名(半角カタカナ)
ken = row[6] # 都道府県名(漢字)
shi = row[7] # 市町村名(漢字)
cho = row[8] # 町域名(漢字)
# 町域名が「以下に掲載がない場合」は、空の要素を入力
if kana_cho == 'イカニケイサイガナイバアイ':
kana_cho = ''
if cho == '以下に掲載がない場合':
cho = ''
# 必要な項目をリストに追加
zip_data.append([zcode, kana_ken, kana_shi, kana_cho, ken, shi, cho])
# 複数行に分割されている町域名を結合
# 郵便番号と「、()」で判別
# リストの件数回繰返し
for i in range(len(zip_data)) :
if i < len(zip_data):
# 一時的に1つ前の町域名を抽出
tmp_kana_cho = zip_data[i-1][3]
tmp_cho = zip_data[i-1][6]
# 1つ前の郵便番号が同じ場合、「、()」で条件分岐
# \はコードを途中で改行する記号
while ((zip_data[i][0] == zip_data[i-1][0]) and ('(' in zip_data[i-1][6]) and ('、' in zip_data[i][6]) and ('(' not in zip_data[i][6]) and (')' not in zip_data[i][6])) \
or ((zip_data[i][0] == zip_data[i-1][0]) and (')' in zip_data[i][6]) and ('(' not in zip_data[i][6])):
# 1つ前の町域名(半角カタカナ)が違う場合、町域名(半角カタカナ)を追加
if zip_data[i][3] != zip_data[i-1][3]:
tmp_kana_cho += zip_data[i][3]
zip_data[i-1][3] = tmp_kana_cho
# 1つ前の町域名(漢字)に現在の町域名(漢字)を追加
tmp_cho += zip_data[i][6]
zip_data[i-1][6] = tmp_cho
# 郵便番号が重複するので、現在のリストを削除
del zip_data[i]
# CSV形式でファイル作成
# UTF-8がいらない場合は以下3行をコメントアウト
with open('20201130_zipcode_all_utf8.csv','wt', encoding='UTF-8', newline='') as f:
writer = csv.writer(f)
writer.writerows(zip_data)
# Shift-JISの場合は、以下3行をアンコメント
# with open('20201130_zipcode_all_shiftjis.csv','wt', encoding='Shift-JIS', newline='') as f:
# writer = csv.writer(f)
# writer.writerows(zip_data)