「今夜、本当に美味しくて速い近所のピザ屋はどこ?」
UberEatsはそれにちゃんと答えてくれない。関連性、プロモーション、アルゴリズムの気分で並べるだけで、「評価と配送時間の最適な組み合わせ」でソートしてくれるわけではない。火曜日の夜8時に本当に欲しいのは後者だ。
そこで、ApifyのUberEats Stores Search by Location and Keywordアクターと約40行のPythonで、その質問にちゃんと答える小さなツールを作ってみた。
アイデア
指定した住所でキーワードに一致するすべての店舗(店名、評価、推定配送時間)を取得し、アプリのデフォルト順ではなく自分でランキングする。評価4.8で配送45分の店は、評価4.5で20分で届く店より必ずしも優れているとは限らない。
手順
クライアントをインストール:
pip install apify-client
データを取得:
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run_input = {
"locations": ["85 Marsh St, Newark, NJ 07114, USA"],
"search_keyword": "pizza",
"max_search_results": 30,
}
run = client.actor("datacach/ubereats-stores-search-by-location-and-keyword").call(run_input=run_input)
items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
各店舗にestimated_time_to_deliveryという文字列(例:"20 min")が返ってくるので、それをパースしてスコアを計算する。評価も重要だが、配送時間が長いほどスコアを下げる:
import re
def parse_minutes(text):
match = re.search(r"\d+", text or "")
return int(match.group()) if match else 60 # unknown time = penalize heavily
def score(store):
rating = store.get("rating") or 0
minutes = parse_minutes(store.get("estimated_time_to_delivery"))
return rating - 0.03 * minutes # tune this weight to taste
ranked = sorted(items, key=score, reverse=True)
for store in ranked[:5]:
print(f"{store['name']:<30} ★{store.get('rating', '?'):<5} {store.get('estimated_time_to_delivery', '?')}")
これで「良い」と「速い」を両立させた上位5店舗が得られる。アプリが勝手に決めた順序ではなく、自分で調整したランキングだ。
CLI化
住所とキーワードを指定して実行できるようにラップする:
import sys
if __name__ == "__main__":
address, keyword = sys.argv[1], sys.argv[2]
# ...call the actor with {"locations": [address], "search_keyword": keyword}...
python fastest_near_me.py "123 Main St, Newark, NJ, USA" "sushi"
拡張アイデア
- 料理ジャンルの比較:同じ住所で「pizza」「sushi」「burgers」をそれぞれ実行し、今夜一番速いジャンルを見つける。
- エリア比較:同じキーワードで複数の住所を調べ、どの地域が配送に強いかを探る。
- スコアの調整:rating_countも加味する。3件の評価で4.8より、500件の評価で4.5の方が信頼できる。
試してみる
無料プラン(1住所、1回10件まで)があるので、まずは自分の住所で試してみてほしい。
- UberEats Stores Search by Location and Keyword — 上記で使用したアクター
もしより良いスコアリング式を考えたら、ぜひコメントで教えてほしい。
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.