見出し画像

Google マイマップに登録した場所を、 KMLファイル経由でワークシートに取り込むプログラム、Python 編

少し前に LibreOffice を使って KML ファイルをワークシートに取り込むことを記事にしたが、Python でもやってみた。

Python では、 KML ファイルから情報を抽出して、csv ファイルにするところまでを処理。

何をするスクリプトか
Google マイマップに登録した場所のデータを 手作業で KML ファイルにエクスポートしたら、そのファイルから場所の名前と緯度経度を読み取って csv ファイルに保存する。

Google マイマップからエクスポートした KML ファイルのフォーマットは、ざっとこんな感じ。

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
    <Document>
        <name>自然観察園地番杭</name>
        <Style id="icon-1899-0288D1-normal">
        ・
        ・
        ・
        <Placemark>
            <name>E30</name>
            <styleUrl>#icon-1899-0288D1-nodesc</styleUrl>
            <Point>
                <coordinates>
                    139.2942621,35.4413589,0
                </coordinates>
            </Point>
        </Placemark>
        ・
        ・
        ・
    </Document>
</kml>

Placemark が登録した場所の数だけある。各 Placemark から name と coordinates を抽出する。

Script 1

自分のレベルに合わせてあまり無理しないで作ったもの。

#-*- coding: UTF-8 -*-
# KML ファイルから名前と緯度経度を読み取る。
import re
import csv
import glob

# タグで囲まれた箇所を抽出する正規表現
pattern_p = re.compile('<Placemark>([\s\S]*?)</Placemark>')
pattern_n = re.compile('<name>([\s\S]*?)</name>')
pattern_c = re.compile('<coordinates>[\s\t\n]*(\d+\.\d+),(\d+\.\d+),\d+[\s\S]*</coordinates>')

# 同じフォルダーにある KML ファイルを処理する
# ただし最初にみつかった KML ファイルだけ
files = glob.glob('./*.kml')
fname = files[0]  

with open(fname, 'r', encoding="utf-8") as myfile:
   s = myfile.read()

# Placemark タグで囲まれた箇所を全て抽出
Placemarks = pattern_p.findall(s)

# name と coordinates を書き出す
with open('./Coordinates.csv', 'w') as csvfile:
   writer = csv.writer(csvfile)

# 個々の Placemark から、name と coordinates を抽出する。
   for Placemark in Placemarks:

   # 名前を抽出
       mName = pattern_n.search(Placemark)
       MyName = mName.group(1)
       
   # 緯度経度を抽出
       mLocation = pattern_c.search(Placemark)
       MyLocation = mLocation.group(2) + ',' + mLocation.group(1)

   # データを書き出す、1行分
       writer.writerow([MyName, MyLocation])
   print(csvfile.read)

この緯度経度を抽出するための正規表現は、マイナスの符号を考慮していない。

※ マイナスの緯度は南半球、マイナスの経度は西周りのエリア。

Script 2

Python の場合、色々と便利なやり方が使えるので、かなり背伸びして作ってみたもの。

・KML ファイルを読み込んで、1回の検索で、必要なすべてのデータを抽出する。finditer()
・正規表現は、より詳細を記述した。
・抽出する要素は、名前付きのグループを定義した。
    'name', 'latitude', 'longitude'
・改行をまたいでマッチさせる re.DOTALL
・全データのリストを作ってから、最後に csv ファイルに書き出すようにした。

# -*- coding: UTF-8 -*-
# KML ファイルから名前と緯度経度を読み取る。

# finditerを使い、一度の検索実行で、全文からすべての name と coordinates を抽出
# KML ファイルには、name が先、coordinates はそれよりも後に現れることを期待する

import re
import csv
import glob

# タグで囲まれた箇所を抽出する正規表現パターン
pattern_p = re.compile('<Placemark>.*?'                     # Placemark 開始タグとすべての文字、最短一致で
                      '<name>(?P<name>.*?)</name>'         # name タグで囲まれた部分、最短一致、名前付きでグループ化
                      '.*?'                                # すべての文字、最短一致で
                      '<coordinates>\s*?'                  # coordinates 開始タグと空白文字(改行を拾うことを狙う)最短一致で
                      '(?P<longitude>-?(\d*\.)?\d+),'      # 経度の値とコンマ、浮動小数点数、名前付きでグループ化
                      '(?P<latitude>-?(\d*\.)?\d+),'       # 緯度の値とコンマ、浮動小数点数、名前付きでグループ化
                      '-?(\d*\.)?\d+'                      # 高度の値、浮動小数点数
                      '\s*?</coordinates>'                 # すべての文字最短一致からの coordinates 終了タグ
                      '.*?</Placemark>',  re.DOTALL | re.VERBOSE)  # すべての文字最短一致からの Placemark 終了タグ

# re.DOTALL で、'.' 特殊文字を、改行を含むあらゆる文字にマッチさせる。re.S としても同じ。
# これにより、改行を含んでマッチさせるパターンを考えなくて済む。
# re.VERBOSE は RE.X に同じ。コメントを書くため。

# 同じフォルダーにある KML ファイルを処理する
# ただし最初にみつかった KML ファイルだけ
files = glob.glob('./*.kml')
fname = files[0]  

# KML ファイルを開き、読み込む
with open(fname, 'r', encoding="utf-8") as myfile:
    kml_text = myfile.read()

# Placemark タグで囲まれた箇所を全て抽出
Placemarks = pattern_p.finditer(kml_text)

# 空のリストを用意する
MyList = []

# Placemark の集合から、Placemark を1つずつ処理する。
for Placemark in Placemarks:

   #  名前
   MyName = Placemark.group('name')

   #  緯度経度のデータを作る
   MyLocation = Placemark.group('latitude') + ',' + Placemark.group('longitude')

   #  "名前"、"緯度,経度" をリストに追加
   MyList.append([MyName, MyLocation])

# データを全部書き出す
with open('./Coordinates.csv', 'w') as csvfile:
   writer = csv.writer(csvfile)
   writer.writerows(MyList)
   print(csvfile.read)


最後に

正規表現を使わない方法もあるが、これは正規表現を学ぶことを目的として作ったものだ。

Python は、楽。LibreOffice Basic は面倒臭い。

以前投稿した Python Script の中で、close() と書いて csv ファイルを閉じていたが、この with ステートメントを使った書き方の場合、ファイルを close() する必要はないのだった。

t.koba

この記事が気に入ったらサポートをしてみませんか?