歩いたら休め

なんでこんな模様をしているのですか?

【Python】GoogleCloudVisionAPIを使って、ホットペッパーの画像で肉々しいお店を判定できないか試してみた

上司から「飲み会のセッティングよろしく!奮発したところで!」という仕事が振られたのですが、そのセッティングや予約を後回しにしてしまい、 直前になってバタバタしてしまっています。

そして、今回の反省を踏まえ、効率よくお店候補を集める方法がないか考えています。

この第一歩として、とりあえずうちの部署には肉好きな方が多いので、

  1. ホットペッパーの希望の価格帯のお店をクローリングする
  2. Google Cloud Vision APIで、肉々しい画像を使っているお店をフィルタリングする

というロジックで、楽にお店の候補を収集するツールが作れないかと考え、 Google Cloud Vision APIを試してみることにしました。

Pythonのサンプルコード

私はPython3系が好きなので、例によってPython3.5で書いています。

import requests
import base64
import json

GOOGLE_CLOUD_VISION_API_URL = 'https://vision.googleapis.com/v1/images:annotate?key='
API_KEY = 'YOUR API KEY' # GCPで登録したAPIのキーに書き換えてください

def request_cloud_vison_api(image_base64):
    api_url = GOOGLE_CLOUD_VISION_API_URL + API_KEY
    req_body = json.dumps({
        'requests': [{
            'image': {
                'content': image_base64.decode('utf-8') # bytes型のままではjsonに変換できないのでstring型に変換する
            },
            'features': [{
                'type': 'LABEL_DETECTION',
                'maxResults': 10,
            }]
        }]
    })
    res = requests.post(api_url, data=req_body)
    return res.json()

def img_to_base64(filepath):
    with open(filepath, 'rb') as img:
        img_byte = img.read()
    return base64.encodebytes(img_byte)

# あらかじめ./niku.jpgに肉画像を保存しておく
img_base64 = img_to_base64('./niku.jpg')
result = request_cloud_vison_api(img_base64)
print(result)

APIを叩いた結果

こちらのお店の

お肉4種の水晶板焼を楽しめる♪ 【熟成肉コース】 時間無制限飲み放題付!全8品 8000円⇒7500円 | ビストロK(焼肉・韓国料理) | ホットペッパーグルメ

こちらの画像を判定したら、このような結果になりました。

f:id:takeshi0406:20160514173423j:plain

{'responses': [{'labelAnnotations': [{'description': 'meal',
     'mid': '/m/0krfg',
     'score': 0.95814741},
    {'description': 'dish', 'mid': '/m/02q08p0', 'score': 0.94838434},
    {'description': 'food', 'mid': '/m/02wbm', 'score': 0.93717068},
    {'description': 'buffet', 'mid': '/m/03vc65', 'score': 0.88017672},
    {'description': 'asian food', 'mid': '/m/01r1z5', 'score': 0.81001866},
    {'description': 'yakiniku', 'mid': '/m/06sr5g', 'score': 0.76712012},
    {'description': 'chinese food', 'mid': '/m/01xw9', 'score': 0.75738144},
    {'description': 'lunch', 'mid': '/m/0jfd5', 'score': 0.69245374},
    {'description': 'restaurant', 'mid': '/m/06l8d', 'score': 0.67063224},
    {'description': 'hot pot', 'mid': '/m/04y0_x', 'score': 0.66542172}]}]}

'yakiniku'というタグが存在していますね

次に、こちらのお店の

【月・火・土・日・祝限定】時間無制限飲み放題!!和牛サーロイン付き♪≪極選コース≫ 7490円 | 炉端焼 うだつ 新橋店(居酒屋) | ホットペッパーグルメ

この画像

f:id:takeshi0406:20160514173730j:plain

{'responses': [{'labelAnnotations': [{'description': 'food',
     'mid': '/m/02wbm',
     'score': 0.95109516},
    {'description': 'dish', 'mid': '/m/02q08p0', 'score': 0.94914007},
    {'description': 'meal', 'mid': '/m/0krfg', 'score': 0.8909772},
    {'description': 'buffet', 'mid': '/m/03vc65', 'score': 0.8491028},
    {'description': 'asian food', 'mid': '/m/01r1z5', 'score': 0.81432122},
    {'description': 'cuisine', 'mid': '/m/01ykh', 'score': 0.79676396},
    {'description': 'yakiniku', 'mid': '/m/06sr5g', 'score': 0.68702412},
    {'description': 'restaurant', 'mid': '/m/06l8d', 'score': 0.67065251},
    {'description': 'chinese food', 'mid': '/m/01xw9', 'score': 0.64552146},
    {'description': 'sukiyaki', 'mid': '/m/01r2v1', 'score': 0.64170885}]}]}

yakiniku, sukiyakiなどのタグが判定されてますね。

次に、そこまで肉っぽくないお店。ふぐ鍋のお店ですね。

★飲放付★一番人気! 泳ぎとらふぐコース 【全7品】8300円(税抜)(3人前~) | とらふぐ亭 銀座店(和食) | ホットペッパーグルメ

f:id:takeshi0406:20160514173909j:plain

{'responses': [{'labelAnnotations': [{'description': 'dish',
     'mid': '/m/02q08p0',
     'score': 0.94715738},
    {'description': 'meal', 'mid': '/m/0krfg', 'score': 0.93616253},
    {'description': 'food', 'mid': '/m/02wbm', 'score': 0.93414766},
    {'description': 'lunch', 'mid': '/m/0jfd5', 'score': 0.69831973},
    {'description': 'asian food', 'mid': '/m/01r1z5', 'score': 0.62586468},
    {'description': 'document', 'mid': '/m/015bv3', 'score': 0.61074013},
    {'description': 'chinese food', 'mid': '/m/01xw9', 'score': 0.58924079},
    {'description': 'seafood', 'mid': '/m/06nwz', 'score': 0.54530984},
    {'description': 'dinner', 'mid': '/m/0jffp', 'score': 0.54398543},
    {'description': 'hors d oeuvre',
     'mid': '/m/0pqdc',
     'score': 0.54184365}]}]}

こちらも'seafood'という判定がされています。Cloud Vision API、かなり精度よさそうです。

思ったこと

意外に精度よくできそうだけど、クローラーを実装するのが面倒だからホットペッパーの機能で自動タグ付けとかやってほしい。

参考にしたサイト

GCPの登録

syncer.jp

Pythonのサンプルコード(こっちでは2系だけど)

daiiz.hatenablog.com

Pythonで画像をbase64にデコードする方法

qiita.com

をそれぞれ参考にさせていただきました