Google Mapsのデータを活用し、便利なGoogle My Mapsを作成する

# TL;DR
店名や住所などからなるCSVのリストに、スクレイピングしたGoogle Mapsの情報を付与すると、使いやすくなります。そのデータをGoogle My Mapsに読み込ませることで、地図上に表示させます。
※スクレイピングは用法・用量を考慮し、ご自分の責任で行なってください。

# ポイント
自治体のキャンペーンなどで、対象店舗リストをPDFやCSVで公開している場合があります。リストなので店名などで検索することは容易ですが、自分の近くにあるお店を探したいなどの場合には不便です。そのため、Google My Mapsを用いて地図上に表示してみました。

合わせて以下の情報をGoogle Mapsから取得して利便性の向上を図りました。
1. カテゴリ（飲食店なら、イタリア料理・焼肉店など）
1. 評価
1. Google MapsでのURL
1. （上記1, 2を組み合わせたもの（例：【4.2_イタリア料理】店名））

上記の情報は、Google My MapsにCSVとして読み込む際に必要となってきます。3つ目のURLはMy Mapsで表示した際に、Google Mapsのお店のページに飛びやすくするために取得しています。4つ目の項目はMy Mapsで地図上にタイトルとして表示すると、一目で分かりやすくなります。

## CSVの例
```csv
店名,住所,電話番号,ホームページ,決済方法 
```

# 手順・実装
今回は、大まかに以下の手順で処理を行います。
1. （PDFなら）何らかのサービスを利用して、PDFからCSVに変換
1. CSVデータの読み込み
1. 読み込んだCSVの各データの長さが同一かを確認する
1. SeleniumでGoogle Mapsを開き、店名をキーにして検索
1. 検索結果の情報を取得し、結果のCSVとして保存
1. 結果のCSVをGoogle My Mapsに、タイトル：`【評価_カテゴリ】店名`、場所：`住所`に設定して読み込む

（あまり書き慣れていないPythonのため、main関数を省略するなど書き方に不備があるかもしれませんが、ご了承ください。）

```python
import csv
import chromedriver_binary
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
import bs4
from bs4 import BeautifulSoup
import requests
import numpy as np


area = '東京' # 店名のみだと絞り込めない場合があるため（住所などを用いてもいい）
filename = 'example.csv'
shop_index = 0 # 店名がある列を指定

def get_info(place_name):
    # 4. SeleniumでGoogle Mapsを開き、店名をキーにして検索
    key = place_name + "%20" + area
    url = 'https://www.google.co.jp/maps/search/' + key
    driver.get(url)
    time.sleep(3) # 検索結果の画面に遷移する間待つ

    page_source = driver.page_source
    soup = BeautifulSoup(page_source, 'html.parser')

    # クラス名でそれぞれの情報を取得しているが、今後変更される可能性あり
    category = ''
    if soup.find(class_="DkEaL u6ijk") is not None:
        category = soup.find(class_="DkEaL u6ijk").text

    rating = ''
    if soup.find(class_="F7nice mmu3tf") is not None:
        rating = soup.find(
            class_="F7nice mmu3tf").contents[0].contents[0].contents[0].text

    return [rating, '【%s_%s】%s' % (rating, category, place_name), driver.current_url, category]


chrome_options = Options()
chrome_options.add_argument("--headless")
driver = webdriver.Chrome(options=chrome_options)

# 2. CSVデータの読み込み
original_data = []
with open(filename, encoding='utf8', newline='') as f:
    csvreader = csv.reader(f)
    for row in csvreader:
        # 必要に応じて行を整形する
        # while len(row) != 7:
        #     row.pop(3)

        original_data.append(row)

# 3. 読み込んだCSVの各データの長さが同一かを確認する
iterator = iter(original_data)
first_row_length = len(next(iterator))
if not all(len(row) == first_row_length for row in iterator):
    raise ValueError('Not all lists have same length!')

result = []
for row in original_data:
    shop = row[shop_index]
    result.append(get_info(shop) + row)
    print(shop)

np_result = np.array(result)
sorted_result = np_result[np.argsort(np_result[:, 0])[::-1]] # Google Mapsの評価の高い順に並べ替え

# 5. 検索結果の情報を取得し、結果のCSVとして保存
result_filename = 'result_' + filename
with open(result_filename, 'w', encoding='utf_8_sig') as file:
    writer = csv.writer(file, lineterminator='\n')
    writer.writerows(sorted_result)
```

<details><summary>requirements.txt</summary><div>

```text:requirements.txt
selenium
chromedriver_binary
requests
bs4
```

</div></details>

# 展望
Google Mapsから情報を取得する部分に時間がかかるため並列化すると良さそうです。

# 参考
- [2021年Googleマップをスクレイピングする方法5選 - note](https://note.com/octoparsejapan/n/n541c451e4179)
- [Pythonで手軽に始めるWebスクレイピング](https://qiita.com/Moh_no/items/a835f77b6b4e3972fbbe)
- [Google Places APIを使って地図上の口コミを分析する方法](https://gaaaon.jp/blog/google_map_api)