【Python】住所が入力されたcsvファイルを読み込み、緯度経度をExcelファイルに出力する

■作成プログラムの概要

・場所の名前と住所を記入しているcsvファイルをインプットに、緯度経度を取得し、結果をExcelファイルに出力する。

■フローチャート

▼メイン処理

▼住所情報読み込み処理

▼緯度経度変換処理

▼Excelファイル出力処理

■プログラム仕様

▼メイン処理

処理名メイン処理
処理概要本プログラムの主処理。
住所情報(csvファイル)を読み込み、緯度経度を取得し、Excelファイルに出力する。
引数なし
戻り値なし
入力処理内容出力
【csvファイル】
住所情報
住所情報読み込み処理を実行する。
緯度経度変換処理を実行する。【コンソール】
住所情報なし
Excelファイル出力処理を実行する。【Excel】
緯度経度付与済み
住所情報

▼住所情報読み込み処理

処理名住所情報読み込み処理
処理概要住所情報を記載している、csvファイルを読み込む。
引数なし
戻り値住所情報
入力処理内容出力
【csvファイル】
住所情報
住所情報読み込む。
input_address.csv
戻り値として住所情報を返す。

▼緯度経度変換処理

処理名緯度経度変換処理
処理概要csvファイルから読み込んだ住所情報から、
APIを使用して、緯度経度を取得する。
なお、取得できなかった場合は「-」とする。
(※)使用するAPI
http://www.geocoding.jp/api/
引数住所情報
戻り値住所情報(緯度経度付与済み)
入力処理内容出力
住所情報のデータに緯度経度の列を追加する。
ループカウンタの初期値(i = 0)をセットする。
■ループ処理:住所情報のデータ件数分繰り返す。
|・緯度経度の初期値「-」をセットする。
|・APIの所定のフォーマットに住所データをセットし、
| 緯度経度を取得する。
|▼条件分岐
||【緯度経度取得結果がエラーの場合】
||・エラーを出力する。
|-----
||【緯度経度取得結果がエラーではない場合】
||・緯度経度を変数にセットする。
|▲
|・緯度経度を住所情報に追加する。
【コンソール】
[error]緯度経度が見つかりませんでした:<住所>
戻り値として、緯度経度追加済みの住所情報を返す。

▼Excelファイル処理

処理名Excelファイル出力処理
処理概要csvファイルの住所情報と緯度経度をExcelファイルに出力する。
引数住所情報+緯度経度
戻り値なし
入力処理内容出力
Excelファイルを作成し、開く。【Excelファイル】
緯度経度
先頭のシートを選択
表のヘッダー:セルに値を入力する。【Excel セル値】
B2:No.
C2:場所
D2:住所
E2:緯度
F2:経度
塗り潰しを黄色に設定
■ループ処理:行数分ループ(1〜2行目まで)
|■ループ処理:セル分ループ(A1、・・・、F2)
||▼条件分岐
|||【セルに値が入力されている場合】
|||・黄色に塗り潰し
||▲
|■
【Excel セル】
黄色
「No.」、「出力開始行」、「ループカウンタ」を初期化
No.=1
出力開始行=3(行目)
ループカウンタ=0
■ループ処理:住所情報のデータ件数分繰り返す
|・「No.」を出力する(B列)。
|・「場所」を出力する(C列)。
|・「住所」を出力する(D列)。
|・「緯度」を出力する(E列)。
|・「経度」を出力する(F列)。
|・「No.」、「出力開始行」、「ループカウンタ」を
| インクリメント
【Excel セル値】
Bi:No.
Ci:場所
Di:住所
Ei:緯度
Fi:経度

i:任意の行数
■ループ処理:Excelの列数分ループ(A〜F列)
|・列幅の最大値を初期化(=0)
|・列番号を取得(A〜F)
|■ループ処理:セル分ループ(A1、・・・、Fi)
||▼条件分岐
|||【セル値の文字数>列幅の最大値】
|||・列幅の最大値=セル値の文字数
||▲
|■
|・列幅の最大値にバッファを設定(+2文字×1.75)
|・列幅を補正する。


i:任意の行数
罫線の種類を設定する(実線、黒色)
セルの罫線を設定する部分をセットする。
(セルの上下左右を対象とする)
■ループ処理:Excelの行数分ループ(1行目〜i行目)
|■ループ処理:セル分ループ(A1〜Fi)
||▼条件分岐
|||【セルに値が設定されている場合】
|||・罫線を設定する。
||▲
|■


i:任意の行数
Excelファイルを保存する。
(保存名:output_address.xlsx)
Excelファイルを閉じる。

■csvファイルレイアウト

・input_address.csv
場所の名前と住所をカンマ「,」区切りで設定する。
※ソースファイルと同階層のフォルダに格納する。

name, address
札幌駅,北海道札幌市北区北6条西4丁目
東京駅,東京都千代田区丸の内1-9-1
新大阪駅,大阪府大阪市淀川区西中島5-16-1
博多駅,福岡県福岡市博多区博多駅中央街1−1
住所ではないデータ,hogehogehogehoge

■Excelファイルレイアウト

・output_address.xlsx
「No.」、「場所の名前」、「住所」、「緯度」、「経度」を表形式で出力する。
なお、存在しない住所の場合、「緯度」、「経度」はハイフン「-」とする。
※ソースファイルと同階層のフォルダに出力する。

■サンプルコード

import requests

from bs4 import BeautifulSoup
import openpyxl
from openpyxl.styles import PatternFill
from openpyxl.styles.borders import Border
from openpyxl.styles.borders import Side
import pandas as pd

# 定数
URL = 'http://www.geocoding.jp/api/'        # 住所を緯度経度に変換するAPI
INPUT_CSVFILE = 'input_address.csv'         # インプットの住所情報ファイル名
OUTPUT_EXCELFILE = 'output_address.xlsx'    # インプットの住所情報ファイル名


def input_address_csv():
    '''
    処理名
        住所情報(csvファイル)読み込み処理
    処理概要
        住所情報を記載している、csvファイルを読み込む
    引数
        なし
    戻り値
        住所情報
    '''
    df_address = pd.read_csv(INPUT_CSVFILE, index_col=None)

    return df_address


def change_latlons(df_csv_data):
    '''
    処理名
        緯度経度変換処理
    処理概要
        csvファイルから読み込んだ住所情報から、
        APIを使用して、緯度経度を取得する。
        なお、取得できなかった場合は「-」とする。
    引数
        住所情報
    戻り値
        住所情報+緯度経度のデータ
    '''
    # 住所情報のデータに緯度経度の列を追加
    df_csv_data = df_csv_data.assign(lat='-')
    df_csv_data = df_csv_data.assign(lon='-')

    # 初期値をセット
    i = 0

    # csvファイルのデータ件数分ループ処理
    for i in range(len(df_csv_data)):
        # 初期値をセット
        tmp_address = ''
        tmp_lat = '-'
        tmp_lon = '-'

        # APIの所定のフォーマットに住所データをセットし、緯度経度を取得する
        tmp_address = df_csv_data.iloc[i][1]
        payload = {"v": 1.1, 'q': tmp_address}
        req = requests.get(URL, params=payload)
        result = BeautifulSoup(req.content, 'xml')

        # 緯度経度取得結果を確認する
        if result.find('error'):
            print("[error]緯度経度が見つかりませんでした:", tmp_address)
        else:
            # 緯度経度を変数にセット
            tmp_lat = result.find('lat').string
            tmp_lon = result.find('lng').string

        # 緯度経度を住所情報データに追加する
        df_csv_data['lat'][i] = tmp_lat
        df_csv_data['lon'][i] = tmp_lon

    return df_csv_data


def output_excel(address_data):
    '''
    処理名
        Excelファイル出力処理
    処理概要
        csvファイルの住所情報と緯度経度をExcelファイルに出力する
    引数
        住所情報+緯度経度
    戻り値
        なし
    '''
    # Excelファイルを作成
    wb = openpyxl.Workbook()

    # 先頭のシートを取得(注意:インデックス番号は0から始まる)
    ws = wb.worksheets[0]

    # 表のヘッダー:セルに値を入力
    ws['B2'] = 'No.'
    ws['C2'] = '場所'
    ws['D2'] = '住所'
    ws['E2'] = '緯度'
    ws['F2'] = '経度'

    # 表のヘッダー:黄色を変更
    fill = PatternFill(patternType='solid', fgColor='ffff00')
    # 行数分ループ(A1〜F1、A2〜F2)
    for row in ws:
        # セル分ループ(A1、・・・、F1、A2、・・・、F2)
        for cell in row:
            # 値が入力されている場合
            if ws[cell.coordinate].value:
                # 塗り潰し
                ws[cell.coordinate].fill = fill

    # 「No.」、「出力開始行(3行目から出力)」、「カウンタ」の初期値をセット
    i_No = 1
    i_row = 3
    i = 0

    # 住所情報の件数分ループ処理
    for i in range(len(address_data)):
        # Noを出力
        ws.cell(i_row, 2).value = i_No
        # 場所を出力
        ws.cell(i_row, 3).value = address_data.iloc[i][0]
        # 住所を出力
        ws.cell(i_row, 4).value = address_data.iloc[i][1]
        # 緯度を出力
        ws.cell(i_row, 5).value = address_data.iloc[i][2]
        # 経度を出力
        ws.cell(i_row, 6).value = address_data.iloc[i][3]

        # インクリメント
        i_No = i_No + 1
        i_row = i_row + 1
        i = i + 1

    # Excelの列分ループ
    for col in ws.columns:
        # 列幅の最長を初期化
        max_length = 0
        # 列番号を取得(A、B、C、・・・、F)
        column = col[0].column_letter

        # セル分ループ(A1、・・・、Ai、・・・、F1、・・・、Fi)
        for cell in col:
            # セル値の文字数より列幅の最長が大きい場合
            if len(str(cell.value)) > max_length:
                # 列幅の最長をセル値の文字数に変更
                max_length = len(str(cell.value))

        # 列幅の最長にバッファを追加(2文字分追加)*1.75
        adjusted_width = (max_length + 2) * 1.75

        # 列幅を補正
        ws.column_dimensions[column].width = adjusted_width

    # 罫線の種類を設定する
    side = Side(style='thin', color='000000')
    # セルの罫線を設定する部分をセット
    border = Border(top=side, bottom=side, left=side, right=side)

    # Excelの行数分ループ(A1〜F1、・・・、Ai〜Fi)
    for row in ws:
        # セル分ループ(A1、・・・、Ai、・・・、F1、・・・、Fi)
        for cell in row:
            # セル値が入力されている場合
            if ws[cell.coordinate].value:
                # 罫線を設定する
                ws[cell.coordinate].border = border

    # Excelファイルを保存
    wb.save(OUTPUT_EXCELFILE)

    # Excelファイルを閉じる
    wb.close()


def main():
    '''
    処理名
        メイン処理
    引数
        なし
    戻り値
        なし
    '''
    # 住所情報(csvファイル)読み込み
    df_input_address = input_address_csv()

    # 住所情報を緯度経度に変換する
    df_input_address_latlon = change_latlons(df_input_address)

    # エクセルに住所と緯度経度を出力する
    output_excel(df_input_address_latlon)


# メイン処理実行
if __name__ == '__main__':
    main()

■実行結果

・コンソールの出力結果

[error]緯度経度が見つかりませんでした: hogehogehogehoge

・Excelファイルの出力結果

コメント

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