2018/09/04

今まで行ったサイゼリヤの位置を地図上に示すクソスクリプトを書く【Python】

タイトルからしておふざけがすぎる.

Sponsored Link

サイゼ大好きマン,Swarmでチェックインしまくる.

サイゼは良い.何が良いかと言うとランチが安いこととドリンクバーをつけてコーヒーを飲みまくれること.……だったのだが,最近はただ習慣になっている気がする.

いつから始めたか,何故始めたかは忘れたがサイゼで飯を食べるたびにSwarmでチェックインしてTwitterに投稿していて,さながら自分のサイゼビッグデータと化している.

データがあるなら図示したい

そこにデータがあるなら何らかの形で視覚化したいと思うのが世の常人の常.今まで行ったサイゼの場所を地図上に表示にしようと思うのは当然であり,義務である.

思いついたら早速コードを書きたくなるが,その前にちょっと方針を整理する.

今まで行ったサイゼのデータ取得

毎回Swarmでチェックイン→Twitter投稿というフローなので,Swarm側でもTwitter側でもデータは取れるが,今回はTwitterの全過去ツイートリクエストでダウンロードできるようになるcsvファイルを入力データとした.ちょっと調べたがSwarmもデータをエクスポートできるらしいので,別にSwarm側のデータを使っても問題はないと思う.

サイゼ店舗の位置情報

最初はサイゼの公式HPからスクレイピングで住所を持ってこようと思ったのだがうまくいかないし,そもそも地図上に図示するなら住所ではなく緯度・経度情報が欲しい.

良い方法を色々探して見つけたのがYahoo!ローカルサーチAPI.以前,施設名を投げると緯度・経度を返すコードを書いて紹介した.

最近もっぱらGoogle Apps ScriptとSlackを連携して各種情報を垂れ流すようにしてみたり,ブックマークレットを書いてみたりとjavascript系のネタが多かったけど,久しぶりに Python ネタを. Sponsored Link 店舗名をキ...

なんか役に立つ風に紹介したが,所詮今回のクソスクリプトの部品にすぎなかったのである.

地図上への図示

これは前から目をつけていたfoliumというライブラリを使うことにした.

目下開発・公開中の「ロケーションスカウター」でも使っているLeafletという地図を処理するjavascriptのライブラリをPythonで使えるようにしたもの.

開発環境

前からぼちぼち使い始めていたGoogle Colaboratory上でコードを書いて実行することにした.WindowsでPythonを使うと文字コードでエラーを吐くことが多いので…….

コード

!pip install folium
!pip install -U -q PyDrive

まずは地図を扱えるようにfoliumをインストールし,過去ツイートcsvファイルをGoogleドライブに上げて読み込めるようにPyDriveもインストール.Colaboratoryでpip installする際は「!」を前につける.

import requests
import folium
import pandas as pd
import re
#csv読み込み
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from google.colab import auth
from oauth2client.client import GoogleCredentials

必要なライブラリのインポート.

#認証
auth.authenticate_user()
gauth = GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)
id = '[ファイルのID]' #ファイルのid
downloaded = drive.CreateFile({'id': id})
downloaded.GetContentFile('data.csv')
df = pd.read_csv('data.csv', usecols=['text']) #textのみ抜き出し

csvファイルを読み込んで読み込み.いつもはcsvのまま無理やりいじったりしてるけど,今回はデータフレームを使う.ツイート本文の列のみを抜き出しておく.

store_name = [] #店名格納リスト
df2 = df[df['text'].str.contains("I'm at サイゼリヤ.*店 in")]
for index, row in df2.iterrows():
  match = re.search('サイゼリヤ.*店', row['text'])
  store1 = row['text'][match.start():match.end()] #サイゼリヤ ○○店を抜き出し
  store2 = store1.split(' ')[1] #店名のほうだけ抜き出す
  store_name.append(store2) #店名を格納
for store in store_name:
  print(store)

ツイート本文に「I'm at サイゼリヤ ○○店 in」が含まれるものだけを抜き出し,正規表現を駆使して店名だけを抜き出す.

イオン横須賀店
大船駅前店
横浜ベイクォーター前店
横浜ベイクォーター前店
ウィング川崎店
京急鶴見東口店
秋葉原中央通り店
新宿西口エルタワー店
南砂町駅前店
新宿西口エルタワー店
新宿西口エルタワー店
田町駅東口八千代橋店
大崎ニューシティ店
元住吉駅前店
新宿西口エルタワー店
日暮里東口店
サミット横浜岡野店
新宿区役所前店
横浜ワールドポーターズ店
横浜ワールドポーターズ店
大船駅前店
東武曳舟店
飯田橋PLANO店
横浜ワールドポーターズ店
青物横丁店
王子駅北口店
四谷三丁目店
秋葉原中央通り店
日ノ出町駅前店
浜松モール街店
秋葉原中央通り店
サミット横浜岡野店
川越マイン店
横浜ベイクォーター前店
日ノ出町駅前店
南流山店
サンポップマチヤ店
神保町店
秋葉原中央通り店
サミット横浜岡野店
神保町店
湘南台ウエストプラザ店

こんな感じで店名を抜き出せる.いよいよクソスクリプト感が出てきた.

from xml.etree import ElementTree as ET
def getSaizeriyaPosition(store_name):
  url = 'https://map.yahooapis.jp/search/local/V1/localSearch?appid=[ID]&query=' + 'サイゼリヤ' + store_name
  data = requests.get(url)
  root = ET.fromstring(data.content)
  #情報なしの時は'None'を返す
  if root.find('.//{http://olp.yahooapis.jp/ydf/1.0}Feature/{http://olp.yahooapis.jp/ydf/1.0}Geometry/{http://olp.yahooapis.jp/ydf/1.0}Coordinates') == None:
    return ['None']
  else:
    position_str = root.find('.//{http://olp.yahooapis.jp/ydf/1.0}Feature/{http://olp.yahooapis.jp/ydf/1.0}Geometry/{http://olp.yahooapis.jp/ydf/1.0}Coordinates').text
    #position_str = root[1][3][1].text でもよい
    position_str_list = position_str.split(',')
    position = [store_name, float(position_str_list[1]), float(position_str_list[0])] #緯度経度の順番入れ替え
    return position #店名,緯度,経度を返す

getSaizeriyaPositionとかいう今年最悪のクソ関数を実装する.詳細は上にリンクを貼ったYahooのAPIの使い方を参照.今思うとPositionよりLocationのほうがよかった.

store_info = [] #店名,緯度,経度格納用リスト
for store in store_name:
  FY = getSaizeriyaPosition(store)
  #情報取得できたか確認.できていればリストに追加
  if FY[0] != 'None':
    store_info.append(FY)
for k in store_info:
  print(k)

いよいよ佳境に.さっき取得した店名リストに入っている店名をすべてクソ関数に突っ込んで緯度・経度を取得する.

['イオン横須賀店', 35.28242722, 139.6621125]
['大船駅前店', 35.353673, 139.533006]
['横浜ベイクォーター前店', 35.46838722, 139.62731778]
['横浜ベイクォーター前店', 35.46838722, 139.62731778]
['ウィング川崎店', 35.5322969, 139.7008731]
['秋葉原中央通り店', 35.70147444, 139.77120361]
['新宿西口エルタワー店', 35.69221611, 139.69752167]
['南砂町駅前店', 35.668048, 139.830504]
['新宿西口エルタワー店', 35.69221611, 139.69752167]
['新宿西口エルタワー店', 35.69221611, 139.69752167]
['田町駅東口八千代橋店', 35.641906, 139.747409]
['元住吉駅前店', 35.564887, 139.654817]
['新宿西口エルタワー店', 35.69221611, 139.69752167]
['日暮里東口店', 35.72898861, 139.7706125]
['サミット横浜岡野店', 35.45923, 139.611181]
['新宿区役所前店', 35.693185, 139.70393028]
['横浜ワールドポーターズ店', 35.4535831, 139.6390339]
['横浜ワールドポーターズ店', 35.4535831, 139.6390339]
['大船駅前店', 35.353673, 139.533006]
['東武曳舟店', 35.71624361, 139.81624194]
['飯田橋PLANO店', 35.70113556, 139.7450775]
['横浜ワールドポーターズ店', 35.4535831, 139.6390339]
['青物横丁店', 35.610464, 139.742424]
['王子駅北口店', 35.7552728, 139.73975735]
['四谷三丁目店', 35.68762556, 139.71988222]
['秋葉原中央通り店', 35.70147444, 139.77120361]
['日ノ出町駅前店', 35.445103, 139.62677]
['浜松モール街店', 34.704627, 137.730558]
['秋葉原中央通り店', 35.70147444, 139.77120361]
['サミット横浜岡野店', 35.45923, 139.611181]
['川越マイン店', 35.90731028, 139.48396111]
['横浜ベイクォーター前店', 35.46838722, 139.62731778]
['日ノ出町駅前店', 35.445103, 139.62677]
['南流山店', 35.84060444, 139.90561111]
['神保町店', 35.696436, 139.759295]
['秋葉原中央通り店', 35.70147444, 139.77120361]
['サミット横浜岡野店', 35.45923, 139.611181]
['神保町店', 35.696436, 139.759295]
['湘南台ウエストプラザ店', 35.39609389, 139.464505]

失笑の漏れるクソデータが手に入る.

map = folium.Map(location=[35.531365, 139.696889], zoom_start=11,attr= '© OpenStreetMap')
for store in store_info:
  folium.Marker([store[1], store[2]], popup=store[0], icon=folium.Icon(color='green', icon='arrow-down')).add_to(map)
map

いよいよ仕上げ.手に入れた緯度・経度にピンを地図上に示す.

今世紀最も役に立たない地図が完成.

おわりに

今までも大概くだらないプログラミングをしてきたがここまでくだらないコードを書いたのははじめてだ.

ただ,やった内容こそくだらないがPythonでここまで簡単に地図をいじれることがわかったのは大きい.GEOJSONなんかと組み合わせたらもっと面白いことはできる……と思う.問題はその「面白いこと」を思いつかないことなんだけども.

0 件のコメント:

コメントを投稿