長崎県の GoTo イート 加盟店をマップ表示

久々に全国すべてで緊急事態宣言・まん延防止〜が解除されて、GoTo イートキャンペーンが復活しました。キャンペーン加盟店を探す際、公式サイトのリストでは調べづらかったので Google マップにプロットしてみました。

長崎県 GoTo イート 加盟店一覧

店舗が2,500軒以上あるため、カテゴリー毎にレイヤーを分けています。ただし、「マイマップ」に設定できるレイヤー上限が10枚のため、マップを2つに分割しています。

ご注意

このマップは2021年10月3日時点の公式サイトに掲示されていた情報を機械的に抽出、マップに表示したものです。最新の情報は公式サイトまたは店舗へお問い合わせください。

マップ Part1

次のカテゴリーの店舗を表示しています。アジア・エスニック.csv、カレー.csv、ファミレス.csv、ホテル内レストラン.csv、焼肉・ホルモン.csv、中華料理.csv、鍋料理.csv、麺類.csv、洋食・西洋料理.csv、和食.csv

※ ブックマークする場合はこちらから新しい画面で開いてください。

マップ Part2

次のカテゴリーの店舗を表示しています。その他.csv、カフェ・喫茶.csv、バー・お酒.csv、パン・スイーツ.csv、居酒屋・ダイニングバー.csv、創作料理・無国籍料理.csv

※ ブックマークする場合はこちらから新しい画面で開いてください。

ウェブサイトの情報を Google マップにプロットする

以下は余談です。上記のマップは次の手順で作成しました。

取得

まず、公式サイトの加盟店一覧のリストを取得します。1〜44ページ目まであるようなので、次のコマンドで取得。

wget https://www.gotoeat-nagasaki.jp/merchant-list/page/{1..44}/

ローカルディレクトリに、index.html、index.html.1 〜 index.html.43 が保存されます。

保存した HTML をエディタで開いて構造を見てみます。

<div class="shop-list-content">
	<div class="shop-list-content-area-cat">
		<div class="shop-list-content-area">
			<i class="fas fa fa-map-marker-alt icon-area"></i>佐世保・佐々エリア</div>
		<div class="shop-list-content-cat">
			<i class="fas fa fa-utensils icon-cat"></i>麺類</div>
	</div>
	<div class="shop-list-content-name">
		麺屋「一刻屋]</div>
	<div class="shop-list-content-add">
		<div class="shop-list-content-add-001">住所:</div>
		<div class="shop-list-content-add-002">佐世保市八幡町2-14</div>
	</div>
	<div class="shop-list-content-tel">
		<div class="shop-list-content-tel-001">電話:</div>
		<div class="shop-list-content-tel-002">0956-24-9807</div>
    </div>

店舗情報は div の class で個別に取得できそうですね。

HTML から CSV へ

Ruby で次のスクリプトを書きました。カレントディレクトリにある HTML ファイルを読み込み、内容を nokogiri を使ってパースし、class の識別子を使って書いてある内容を取得、カテゴリー別に CSV に出力しています。

#!ruby
# coding: utf-8

require 'nokogiri'

Dir.glob("./*.html*") do |f|
  html = File.read(f)
  doc = Nokogiri::HTML.parse(html)
  doc.css('.shop-list-content').each do |x|
    name = x.css('.shop-list-content-name').first.content.strip
    area = x.css('.shop-list-content-area').first.content.strip
    cat  = x.css('.shop-list-content-cat').first.content.strip
    add  = x.css('.shop-list-content-add-002').first.content.strip
    tel  = x.css('.shop-list-content-tel-002').first.content.strip
    target = "./#{cat}.csv"
    unless File.exist?(target)
      File.write(target, '"名前","エリア","カテゴリー","住所","電話番号"' + "\n")
    end
    add = "長崎県#{add}"
    File.open(target, "a") do |f|
      f.puts [name, area, cat, add, tel].map {|x| "\"#{x}\"" }.join(',')
    end
  end
end

実行すると、カレントトディレクトリに「和食.csv」「洋食・西洋料理.csv」といったファイルが出来ます。それぞれの内容はこんな感じに。

"名前","エリア","カテゴリー","住所","電話番号"
"cafenanami","五島・新上五島・小値賀エリア","洋食・西洋料理","長崎県南松浦郡新上五島町有川郷茂串2426-16","0959-42-5242"
"Bistro弐番館","佐世保・佐々エリア","洋食・西洋料理","長崎県佐世保市有福町99-8","0956-59-6520"
"キッチンはーとらんど","佐世保・佐々エリア","洋食・西洋料理","長崎県佐世保市鹿子前町761","070-5278-8885"
"カフェ.5","佐世保・佐々エリア","洋食・西洋料理","長崎県佐世保市万津町7-6フクヤビル1F","0956-22-8505"
"レストランprimrose","長崎エリア","洋食・西洋料理","長崎県長崎市古川町3-3若喜屋ビル2階","095-829-2115"
"対馬バーガーKIYO","壱岐・対馬エリア","洋食・西洋料理","長崎県対馬市厳原町大手橋1052","0920-52-0873"

マップにインポートする際、1行目にヘッダが必要なので付与しています。

CSV を Google マップに取り込み

Google マップの「マイマップ」を開き、新しいマップを作成します。新しいレイヤーの「インポート」をクリックすると、CSV ファイルをデータソースとしてアップロードすることができます。

CSV ファイルをアップロードすると、プロットさせる位置情報が記録されたカラムを聞いてきます。

今回は「住所」カラムに住所の文字列を入れているので、それに基いて座標を決めさせましょう。

次にマーカータイトルです。「名前」を選択しました。ここで選択されなかった情報もすべて取り込まれ、マーカーの詳細を見ると表示されるようになります。「完了」を押すと取り込まれます。

こんな感じ。便利ですねー。カラム名やカラムの数は自由に設定することができます。マップにプロットする以上、住所文字列や緯度経度情報、ジオコード等の情報は必須です。

修正

ただインポートしただけでは、住所文字列を正しく解釈できないものもいくつかありました。上図のように、エラーが発生したデータについてはお知らせしてくれます。「データ表を開く」をクリックすると表が表示されます。

エラーになっているのは赤いところです。わかりやすい。住所部分にカーソルをフォーカスすると、この画面で内容を変更することができます。どうやら建物名や枝番まで入っている住所だと位置特定ができない模様。

手作業で一つずつ不要な部分を削除してあげると、エラーが解消できました。あとは見易いように、アイコン色などを設定してあげて完成です。

まとめ

最初から CSV でデータソースを公開してくれたら、HTML からパースする必要もないので手間がかかりません。ダウンロードした CSV を Google マップにインポートするだけです。

でも今回は自治体の公開情報としてはまだマシな方で、県の宿泊助成金キャンペーンPDF ファイルで公開されています。PDF の解析をした事がある方なら分かると思いますが、組版なのでテーブルのナリをしていても簡単に解析できるもんじゃないんですよね。元は Excel か何かだと思うので、わざわざデータの活用性を殺した上で公開しているのはどうかと…。

佐世保市の「佐世保市内でゆったり宿泊キャンペーン」は、シンプルな HTML のテーブルなので今回と同様にプロットできそうです。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください