はじめに
こんにちは
Advent Calendar 2022
始まりましたね。私、初めての参加となり、非常にワクワクしとります。
まだ埋まってない日程があったりと不安はありますが、せっかくなのでみんなで楽しんで記事を書いて走り切りたい気持ちです。
では3日目、行きましょう!
この記事は TLB Enjoy Developers Advent Calendar 2022 の3日目の記事です。
さて今回の記事ですが、もう時が経つのも早いもので2022年も残り1ヶ月を切りました
師走といえばやっぱり忘年会
忘年会といえば飲み会
飲み会といえば...
ビールですよね?
私も東京に上京して早1年が経過しました。
上野に新宿、渋谷に赤羽、神田、新橋、北千住、品川、下北沢、巣鴨、etc...
ありがたいことにいろんな場所でお友達や同僚、いろんな方と飲ませていただきました。
上京するまでは大阪に住んでおりましたので、大阪でもいろんなところで飲み歩いておりました。
で、思ったことがあるんです。
東京の生ビール、高くないですか??
大阪では大体300円台、安くて99円とか...あまり500円を超えることはなかったと思います。
それが上京してからは400円台は当たり前、高くて500〜600円もしばしば...
1回の飲み代もバカにならない...
大阪から上京した友人も東京での飲みは1回5〜6000円がデファクトスタンダードと認識しているようです。
ここいらでいっちょ東京の生ビール価格と大阪の生ビール価格、
どれくらい違うのか検証したいと思ったのが今回の記事のテーマでございます。
目次
使用技術
- Python 3.10.8
- beautifulsoup4 4.11.1
- requests 2.28.1
※細かいライブラリ系は省略します
検証方法
検証方法は至ってシンプルです。
グルメサイトに登録されているあらゆる店舗のドリンクメニューページにて「生ビール(生中)」の価格をスクレイピングし、東京と大阪の生ビールそれぞれの平均値を算出することで、
いかに東京の生ビールが高いかをあらためて世間に訴えかけるわけです。
絞り込む要素として
- 住所が東京都内、大阪府内であること
- 飲食店のジャンルとしては居酒屋であること
が最低限必須項目です。
ビールの詳細については実装しながら説明します!
対象サイトの選定
結論から今回はホットペッパーグルメさんを利用したいと思います。
理由は下記の通りです。
- ドリンクページのURLに統一性がある
- APIが提供されている
詳しくご説明いたします。
ドリンクページのURLに統一性がある
ぐるなび、食べログなども視野に入れておりましたが、ドリンクページのURLが統一されていたのはホットペッパーグルメでした。
ある飲食店のURLを引用します。
https://www.hotpepper.jp/strJ000960806/drink/
ドメインの後に、店舗IDらしきもの、
そしてdrink
ん〜〜実にシンプル、素晴らしい!
例えばぐるなびさんですと、
https://r.gnavi.co.jp/gajn110/menu4/
https://r.gnavi.co.jp/n187308/menu2/
サブディレクトリにmenu4やmenu2、drinkとバラエティに豊富でしたので、
ドリンクメニューページに辿り着くのにやや工数がかかりそうです。
APIが提供されている
これは残念ながらぐるなびや食べログは以前は提供していたそうですが、現在は廃止されているようです。
正直1番目の理由でホットペッパー一択なんですが、
ホットペッパーに関しては現在もAPIを提供していただいておりますので、もう確定です。
さすがリクルート。ありがとうございます。
こちらのリファレンスを参照すると、店舗を絞って店舗IDを取得できそうです。
いかにスクレイピングするURLリストを素早く作っていくかが肝になるので、本当にありがたいですね。
利用規約
ここで一つ重要なポイント。
スクレイピングはサイトによっては利用規約違反となることもあります。
利用規約で明示的に「スクレイピングの禁止」と記載があればあきらめましょう。
幸いスクレイピングに関する記載はなさそうです。
引っかかる点とすれば第12条
【18】不正なプログラム・スクリプトなどを用いて、サーバーに負荷を与える行為
こちらはスクレイピング時にしっかりtime.sleep
使って極力負荷をかけないように注意しましょう。
実装
API
早速APIをポチポチ叩いてみてみます。
叩き方の詳細はぜひリファレンスを確認してみてくださいね。
レスポンスフィールドのこちらが飲食店を一意に取得できそうなIDです。
なるほど、10185軒の飲食店がヒットしました。
(result_available
がヒットした店舗数です。)
id
をキーに店舗IDが取れているのがわかりますね。
では大阪の居酒屋はどうでしょう。
.......
は?
早くも大阪と東京の絶大な格差を垣間見た気がします。
ここまで店舗数に差があるとは思ってませんでした。
URLリスト生成
気を取り直して
こちらのAPIをPythonで叩いて、URLリストを生成していきましょう。
for i in range(1, result_available, 100):
params = {
"key": "API KEY", # APIキー。取得方法はリファレンス参照
"large_area": "Z011", # エリアコード:東京
"genre": "G001", # 飲食店種別:居酒屋
"format": "json",
"count": 100, # 1ページあたりの店舗数
"type": "lite", # レスポンスフィールドを少なめにする
"start": i # 何番目の店舗から表示するか
}
p = urllib.parse.urlencode(params)
url = 'http://webservice.recruit.co.jp/hotpepper/gourmet/v1/?' + p
ざっとこんな感じでURL生成のリストを生成していきます。
重要なのは
- 東京都内・大阪府内であること
- 居酒屋であること
1ページあたり最大100軒表示なので、先ほどAPIを叩いて得たresult_available
の値に達するまで表示する店舗を100軒ずつ回していきます。
drink_url=f'https://www.hotpepper.jp/str{shop_id}/drink/'
取得したJSONからid
のみを取得してURLを生成してリスト化したテキストファイルを作成します。
スクレイピング
メインディッシュです。
request
とbeautifulsoup
を用いて先ほど取得したURLにアクセスして、生ビールの価格を取得していきます。
まずはドリンクメニューのサイトを検証ツールを用いてよく観察して、どのタグ、どの要素、どのDOMを取得していくか探してみます。
h4
, class="firstChild"
, class="price"
あたりがキーになってきそうです。
url = 'https://www.hotpepper.jp/strJ001017281/drink/'
html_text = requests.get(url).text
soup = BeautifulSoup(html_text, 'html.parser')
for h4 in soup.find_all('h4'):
print(h4)
適当なページからh4
タグのみ取得してみます。
<h4 class="firstChild">キリン一番搾り 生ビール</h4>
<h4 class="firstChild">瓶ビール(中瓶)</h4>
<h4 class="firstChild">【ノンアルコールビールテイスト飲料】キリン ゼロイチ</h4>
<h4 class="firstChild">ホッピーセット/黒ホッピーセット</h4>
<h4 class="firstChild">ジムビーム</h4>
<h4 class="firstChild">角瓶</h4>
<h4 class="firstChild">メーカーズマーク</h4>
<h4 class="firstChild">ジョニーウォーカー ゴールドラベル</h4>
<h4 class="firstChild">生ジンジャー/コーラ&レモン/エルダーフラワー</h4>
<h4 class="firstChild">山梨産 白桃/長野産 シャインマスカット/馬路村のゆず・はちみつ</h4>
<h4 class="firstChild">シールド乳酸菌&生レモン/瀬戸内レモン</h4>
素晴らしい!!!
どうやらドリンクの名称のみがh4
タグに割り当てられているようです。
ではそのh4
タグのすぐ後ろのp
タグがclass="price"
であればそのドリンクの価格が取得できそうです!!
従ってh4
タグの名前が「生ビール」であれば、その後のp
タグ、class="price"
を取得すれば、
その店舗の生ビールの価格が手に入るわけですね!!
と、そんなに甘くなく、店舗によって「生ビール」の表記がバラエティに富んでいました。
なるほど、「生ビール」ではなく銘柄を書くスタイルですね
てか店舗によって背景色とか変えれるんですね...
ピッチャーは想定外
商品名に価格をまとめるな
価格を最後にまとめるな
あと中便
少し飲みたい方は是非!とちゃいますねん
おいおいおいおいおいお
あくまでも私は生中!!ジョッキ!!発泡酒ではない生ビール!!!!の価格が知りたいんです。
色々試行錯誤を経て取得対象となるドリンクメニューに以下のような制約をかけました。
beer = '生ビール'
raw_beer = '生中'
premium = 'プレミアムモルツ'
premium1 = 'プレミアム・モルツ'
super_dry = 'スーパードライ'
malts = 'ザ・モルツ'
yebisu = 'YEBISU'
yebisu1 = 'エビス'
kirin = '一番搾り'
sapporo = 'サッポロ'
こちらは取得対象となるh4
タグのキーワードです。
生ビール、生中をベースにホットペッパーでよく見かけたビールの銘柄をいくつかピックアップしました。
(ちなみに私の好きな銘柄はエビスです。)
self = 'セルフ'
mega = 'メガ'
king = 'キング'
pitcher = 'ピッチャー'
big = '大'
mini = '小'
glass = 'グラス'
mouse = '一口'
vase = '瓶'
vase_kana = 'びん'
baka = 'バカ'
こちらは除外キーワードになります。
「生ビール」と記載があっても「セルフサービスでこの値段!」「中瓶」「ピッチャー」「メガ生ビール」「生大」といったような下位互換な(人によっては上位互換かもしれない)ワードがありましたので省きます。
これらは価格を無闇に吊り上げたり、あるいは引き下げたりする要素となりますので危険です。
「バカ」はさすがに少数派ですが、偶然見つけてしまったので省きます。
あと、クラフトビールもありましたが、さすがにここまで細かく絞っていくとキリがないので諦めます。
おそらく大阪も東京も一定数店舗があると思いますので、ここは算出の対象に含めちゃいましょう。
取得結果がこちらです
こんな感じで、店舗IDと生ビール価格をJSONで保存することができました。
これでもやはり、
- URLの有効期限切れ(掲載終了など)
- ビール価格が掲載されていない店舗 etc...
といった理由で価格が取れていない店舗がいくつかありました。
しかしこれでもある程度十分量取得できましたので今回はヨシとしましょう。
解析
先ほど生成したJSONを読み込んで、解析していきましょう!
価格は文字列として保管されております。
ここを数値だけにの価格リストを生成し、最終的に平均値を算出する流れです。
price_list = []
exist_beer_shop = 0
for price_str_list in price_data.values():
if not price_str_list:
continue
exist_beer_shop += 1
for price_str in price_str_list:
prices = re.findall(r"\d+", price_str.replace(',', ''))
for price in prices:
if int(price) > beer_max_price:
continue
price_list.append(int(price))
とりあえずざっとこんな感じです。
price_data
が先ほどのJSONを読み込んだデータですね。
re.findall(r"\d+", price_str.replace(',', ''))
ここの部分ですが、価格文字列から数値(価格)だけを抽出するに当たって、
1,000円
とか2,240円
とか1000円を超えるとカンマ区切りになり、
それぞれが別の数値としてリストに保存されてしまうので、あらかじめカンマは消しておきます。
([2, 240, ...]みたいな)
if int(price) > beer_max_price:
ここは先ほど取得したJSONでもやはり高額な箇所がいくつかありました。
しかしサイトを見ると、ビッグサイズなビールであったり、飲み放題価格であったりしましたので、
今回は1500円を超えると一般的な生中と見做さないようにしておきます。
結果
お待たせしました。
ようやく結果発表です。
東京の生ビール価格
生ビールが存在した店舗数 : 7111
生ビールリストの要素数 : 8998
生ビールの平均値 : 547.627695043343
生ビールの最安値 : 110
生ビール価格が取得できたのは10185軒中7111軒
その中で生ビールに関する価格を取得できた数は8998ビール
平均価格は547.6円!
高いですね...
最安値110円!!??
いくらなんでも安すぎでは...??
いやいや虎ノ門でこの価格は絶対無理でs...
...やばそう
大阪の生ビール価格
さぁ、我が故郷よ、その真価を発揮してくれ
生ビールが存在した店舗数 : 3181
生ビールリストの要素数 : 4033
生ビールの平均値 : 483.3994545003719
生ビールの最安値 : 0
生ビール価格が取得できたのは4696軒中3181軒
その中で生ビールに関する価格を取得できた数は4033ビール
平均価格は483.3円!
んーー・・・
思ってたんとちょっとちゃいますね。
もっと差が開くかと思いきや、その差僅かおよそ60円・・・。
いやそれよりも
最安値0円??
天満ならやってくれそうな気がs...
あっ....(察し
おわりに
年末は天満で飲むことにしました
明日は@KeiFunahashiさんの記事です!!
乞うご期待を!!