【Python】東京の生ビールは高すぎる！！

# はじめに
こんにちは

**Advent Calendar 2022**

始まりましたね。私、初めての参加となり、非常に**ワクワク**しとります。
まだ埋まってない日程があったりと不安はありますが、せっかくなので**みんなで楽しんで記事を書いて走り切りたい気持ち**です。

**では3日目、行きましょう！**

:::note info
この記事は [TLB Enjoy Developers Advent Calendar 2022](https://qiita.com/advent-calendar/2022/tlb-enjoy) の3日目の記事です。
:::


**さて今回の記事ですが、もう時が経つのも早いもので2022年も残り１ヶ月を切りました**

#### 師走といえばやっぱり忘年会

#### 忘年会といえば飲み会

#### 飲み会といえば...

### ビールですよね？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/ed67f3ed-f6a1-3eb2-309d-8717f1d080e5.png)


私も東京に上京して早1年が経過しました。
上野に新宿、渋谷に赤羽、神田、新橋、北千住、品川、下北沢、巣鴨、etc...
ありがたいことにいろんな場所でお友達や同僚、いろんな方と飲ませていただきました。

上京するまでは大阪に住んでおりましたので、大阪でもいろんなところで飲み歩いておりました。

**で、思ったことがあるんです。**

#### 東京の生ビール、高くないですか？？

![money_saifu_kara_man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/680f177e-467e-c5ce-dfc4-3e7c2f769519.png)

大阪では大体**300円台**、安くて**99円**とか...あまり500円を超えることはなかったと思います。

それが上京してからは**400円台は当たり前**、高くて**500〜600円**もしばしば...

１回の飲み代もバカにならない...

大阪から上京した友人も東京での飲みは１回5〜6000円がデファクトスタンダードと認識しているようです。

ここいらでいっちょ**東京の生ビール価格と大阪の生ビール価格**、
**どれくらい違うのか検証したい**と思ったのが今回の記事のテーマでございます。

# 目次
- [はじめに](#はじめに)
- [使用技術](#使用技術)
- [検証方法](#検証方法)
- [対象サイトの選定](#対象サイトの選定)
    - [ドリンクページのURLに統一性がある](#ドリンクページのurlに統一性がある)
    - [APIが提供されている](#apiが提供されている)
- [実装](#実装)
    - [API](#api)
    - [URLリスト生成](#urlリスト生成)
    - [スクレイピング](#スクレイピング)
    - [解析](#解析)
- [結果](#結果)
    - [東京の生ビール価格](#東京の生ビール価格)
    - [大阪の生ビール価格](#大阪の生ビール価格)
- [おわりに](#おわりに)



# 使用技術
- Python 3.10.8
- beautifulsoup4 4.11.1
- requests 2.28.1

※細かいライブラリ系は省略します

# 検証方法

検証方法は至ってシンプルです。

**グルメサイト**に登録されているあらゆる店舗のドリンクメニューページにて「**生ビール（生中）」の価格**を**スクレイピング**し、**東京と大阪の生ビールそれぞれの平均値**を算出することで、
**いかに東京の生ビールが高いかをあらためて世間に訴えかけるわけです。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/460baccb-5246-77b9-cbfd-0e3e9bad41a2.png)


絞り込む要素として
- 住所が**東京都内、大阪府内**であること
- 飲食店のジャンルとしては**居酒屋**であること
が最低限必須項目です。

ビールの詳細については実装しながら説明します！

# 対象サイトの選定

結論から今回は**ホットペッパーグルメ**さんを利用したいと思います。
理由は下記の通りです。

1. **ドリンクページのURLに統一性がある**
1. **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を提供していただいておりますので、もう確定です。
さすがリクルート。ありがとうございます。

https://webservice.recruit.co.jp/doc/hotpepper/reference.html

こちらのリファレンスを参照すると、店舗を絞って店舗IDを取得できそうです。

![スクリーンショット 2022-12-03 1.41.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/8984856a-0062-0036-5b6f-1e58e5bd4f4f.png)

いかにスクレイピングするURLリストを素早く作っていくかが肝になるので、本当にありがたいですね。

#### 利用規約
ここで一つ重要なポイント。

スクレイピングはサイトによっては利用規約違反となることもあります。
利用規約で明示的に「**スクレイピングの禁止**」と記載があればあきらめましょう。

https://cdn.p.recruit.co.jp/terms/hpg-t-1002/index.html

幸いスクレイピングに関する記載はなさそうです。

引っかかる点とすれば第１２条
> 【18】不正なプログラム・スクリプトなどを用いて、サーバーに負荷を与える行為

こちらはスクレイピング時にしっかり`time.sleep`使って極力負荷をかけないように注意しましょう。


# 実装

## API

早速APIをポチポチ叩いてみてみます。
叩き方の詳細はぜひリファレンスを確認してみてくださいね。

![スクリーンショット 2022-12-03 1.50.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/0eb7da4f-171a-0190-b819-db875b4edb51.png)

レスポンスフィールドのこちらが飲食店を一意に取得できそうなIDです。

実際に**東京**の**居酒屋**で絞り込んでみましょう。
![スクリーンショット 2022-12-03 2.01.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/1a815381-8b55-c673-af11-6ab7798ccbd3.png)


なるほど、**10185軒**の飲食店がヒットしました。
(`result_available`がヒットした店舗数です。)
`id`をキーに**店舗ID**が取れているのがわかりますね。

では**大阪**の**居酒屋**はどうでしょう。

![スクリーンショット 2022-12-03 2.03.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/6fbf0be9-c022-4ace-e6e0-379c39221c17.png)

**.......**

![スクリーンショット 2022-12-03 2.05.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/66294329-0eb8-5708-891a-b953b591e6b6.png)

**は？**

早くも**大阪と東京の絶大な格差**を垣間見た気がします。
ここまで店舗数に差があるとは思ってませんでした。

## URLリスト生成

**気を取り直して**
こちらのAPIをPythonで叩いて、URLリストを生成していきましょう。

```python
for i in range(1, result_available, 100):
    params = {
        "key": "API KEY", # APIキー。取得方法はリファレンス参照
        "large_area": "Z011", # エリアコード：東京
        "genre": "G001", #　飲食店種別：居酒屋
        "format": "json",
        "count": 100, # １ページあたりの店舗数
        "type": "lite", # レスポンスフィールドを少なめにする
        "start": i # 何番目の店舗から表示するか
    }
    p = urllib.parse.urlencode(params)
    url = 'http://webservice.recruit.co.jp/hotpepper/gourmet/v1/?' + p
```

ざっとこんな感じでURL生成のリストを生成していきます。
重要なのは
- 東京都内・大阪府内であること
- 居酒屋であること

１ページあたり最大100軒表示なので、先ほどAPIを叩いて得た`result_available`の値に達するまで表示する店舗を100軒ずつ回していきます。

```python
drink_url=f'https://www.hotpepper.jp/str{shop_id}/drink/'
```

取得したJSONから`id`のみを取得してURLを生成してリスト化したテキストファイルを作成します。

ざっとこんな感じです。
![スクリーンショット 2022-12-03 2.17.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/bd3cf8aa-0a25-08ed-84f8-8e1d34fc5e4e.png)

## スクレイピング

**メインディッシュ**です。

`request`と`beautifulsoup`を用いて先ほど取得したURLにアクセスして、生ビールの価格を取得していきます。

まずはドリンクメニューのサイトを**検証ツール**を用いてよく観察して、どのタグ、どの要素、どのDOMを取得していくか探してみます。
![スクリーンショット 2022-12-03 2.30.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/836ffb52-b0c3-40d6-b080-c205380c247d.png)

`h4`, `class="firstChild"`, `class="price"`あたりがキーになってきそうです。

```python
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">生ジンジャー/コーラ&amp;レモン/エルダーフラワー</h4>
<h4 class="firstChild">山梨産 白桃/長野産 シャインマスカット/馬路村のゆず・はちみつ</h4>
<h4 class="firstChild">シールド乳酸菌＆生レモン/瀬戸内レモン</h4>
```

**素晴らしい！！！**
どうやらドリンクの名称のみが`h4`タグに割り当てられているようです。
ではその`h4`タグのすぐ後ろの`p`タグが`class="price"`であればそのドリンクの価格が取得できそうです！！

従って`h4`タグの名前が「**生ビール**」であれば、その後の`p`タグ、`class="price"`を取得すれば、
**その店舗の生ビールの価格が手に入るわけですね！！**

と、そんなに甘くなく、**店舗によって「生ビール」の表記がバラエティに富んでいました。**

**いくつか例を挙げましょう。**
**パターン1**
![スクリーンショット 2022-12-03 2.43.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/c98da296-f753-5128-9ad5-75216498f206.png)

**なるほど、「生ビール」ではなく銘柄を書くスタイルですね**
てか店舗によって背景色とか変えれるんですね...

**パターン2**
![スクリーンショット 2022-12-03 2.43.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/c007d1b3-b407-41c7-8520-eba98bc44176.png)

**ピッチャーは想定外**

**パターン3**
![スクリーンショット 2022-12-03 2.44.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/8101ea9a-70f0-81b7-f21d-9f22495e2ce1.png)

**商品名に価格をまとめるな**

**パターン4**
![スクリーンショット 2022-12-03 2.44.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/539be700-a72a-f8d0-8002-c99503b3662a.png)

**価格を最後にまとめるな**
あと中便

**パターン5**
![スクリーンショット 2022-12-03 2.43.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/81d4d274-5095-0581-b567-c3fd7a729708.png)

**少し飲みたい方は是非！とちゃいますねん**

**パターン6**
![スクリーンショット 2022-12-03 2.45.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/028c85ac-9713-4a72-ca35-74d3a55b4267.png)

**おいおいおいおいおいお**

---

あくまでも私は**生中！！ジョッキ！！発泡酒ではない生ビール！！！！の価格**が知りたいんです。
色々試行錯誤を経て取得対象となるドリンクメニューに以下のような制約をかけました。

```python
beer = '生ビール'
raw_beer = '生中'
premium = 'プレミアムモルツ'
premium1 = 'プレミアム・モルツ'
super_dry = 'スーパードライ'
malts = 'ザ・モルツ'
yebisu = 'YEBISU'
yebisu1 = 'エビス'
kirin = '一番搾り'
sapporo = 'サッポロ'
```

こちらは取得対象となる`h4`タグのキーワードです。
生ビール、生中をベースにホットペッパーでよく見かけたビールの銘柄をいくつかピックアップしました。
（ちなみに私の好きな銘柄はエビスです。）


```python
self = 'セルフ'
mega = 'メガ'
king = 'キング'
pitcher = 'ピッチャー'
big = '大'
mini = '小'
glass = 'グラス'
mouse = '一口'
vase = '瓶'
vase_kana = 'びん'
baka = 'バカ'
```

こちらは除外キーワードになります。
「生ビール」と記載があっても「セルフサービスでこの値段！」「中瓶」「ピッチャー」「メガ生ビール」「生大」といったような下位互換な（人によっては上位互換かもしれない）ワードがありましたので省きます。
これらは**価格を無闇に吊り上げたり、あるいは引き下げたりする要素**となりますので危険です。

**「バカ」はさすがに少数派ですが、偶然見つけてしまったので省きます。**
![スクリーンショット 2022-12-03 3.02.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/b0b6c573-830c-2c43-558e-38e895d3327c.png)

あと、クラフトビールもありましたが、さすがにここまで細かく絞っていくとキリがないので諦めます。
おそらく大阪も東京も一定数店舗があると思いますので、ここは算出の対象に含めちゃいましょう。

![スクリーンショット 2022-12-03 2.45.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/90ce89dd-346f-45fc-c140-af1c917dd0d9.png)

**取得結果がこちらです**

![スクリーンショット 2022-12-03 3.07.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/e6a1e206-eb08-44fa-2d23-fdb48f957b2a.png)

こんな感じで、**店舗IDと生ビール価格**をJSONで保存することができました。

これでもやはり、
- **URLの有効期限切れ（掲載終了など）**
- **ビール価格が掲載されていない店舗**  etc...

といった理由で価格が取れていない店舗がいくつかありました。

しかしこれでもある程度十分量取得できましたので今回はヨシとしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/268d616c-712b-04ea-26e2-372187730f98.png)


## 解析

先ほど生成したJSONを読み込んで、解析していきましょう！

価格は文字列として保管されております。
ここを数値だけにの価格リストを生成し、最終的に平均値を算出する流れです。

```python
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を読み込んだデータですね。

```python
re.findall(r"\d+", price_str.replace(',', ''))
```

ここの部分ですが、**価格文字列から数値（価格）だけを抽出**するに当たって、
`1,000円`とか`2,240円`とか1000円を超えると**カンマ区切り**になり、
**それぞれが別の数値**としてリストに保存されてしまうので、あらかじめカンマは消しておきます。
([2, 240, ...]みたいな)

```python
if int(price) > beer_max_price:
```

ここは先ほど取得したJSONでもやはり高額な箇所がいくつかありました。
しかしサイトを見ると、ビッグサイズなビールであったり、飲み放題価格であったりしましたので、
今回は**1500円を超えると一般的な生中と見做さない**ようにしておきます。

# 結果

お待たせしました。
ようやく結果発表です。

### 東京の生ビール価格

```
生ビールが存在した店舗数 : 7111
生ビールリストの要素数 : 8998
生ビールの平均値 : 547.627695043343
生ビールの最安値 : 110
```

生ビール価格が取得できたのは**10185軒中7111軒**
その中で生ビールに関する価格を取得できた数は**8998ビール**

**平均価格は547.6円！**

高いですね...

**最安値110円！！？？**
いくらなんでも安すぎでは...？？

https://www.hotpepper.jp/strJ001226073/drink

いやいや虎ノ門でこの価格は絶対無理でs...

![スクリーンショット 2022-12-03 3.45.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/8f99567c-32cf-66de-db5f-5b3e9d7ef155.png)

...やばそう

### 大阪の生ビール価格

さぁ、我が故郷よ、その真価を発揮してくれ

```
生ビールが存在した店舗数 : 3181
生ビールリストの要素数 : 4033
生ビールの平均値 : 483.3994545003719
生ビールの最安値 : 0
```

生ビール価格が取得できたのは**4696軒中3181軒**
その中で生ビールに関する価格を取得できた数は**4033ビール**

**平均価格は483.3円！**

んーー・・・
思ってたんとちょっとちゃいますね。
もっと差が開くかと思いきや、その差僅かおよそ60円・・・。

いやそれよりも
**最安値0円？？**

https://www.hotpepper.jp/strJ001224482/drink/

天満ならやってくれそうな気がs...

![スクリーンショット 2022-12-03 3.52.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873426/2853cab0-f301-f381-840a-0045977de739.png)

あっ....(察し


# おわりに

年末は天満で飲むことにしました

---
明日は@KeiFunahashiさんの記事です！！
乞うご期待を！！