UberEatsの管理画面は結構スクレイプし難い
所用でUberEatsの管理画面をスクレイプする必要があり、プログラムを組みました。ただ、なかなかスクレイプが面倒だったので、知見をまとめておきたいと思います。
今回、やりたいことの要件としては、レポートのファイルでは取ることの出来ない、注文メニューと顧客の誰がフィードバックレビューしたかという情報を取ることで、そこにフォーカスした話しになります。
レポートに関して
まず、レポートに関しては、多少面倒ではありますが、手動でのデータ取得にしました。
基本的には、注文履歴をベースにデータを作りました。注文履歴のUUIDをベースに、そこに紐付ける形で、商品エラーやフィードバックを入れ込むようなデータ構造にしています。
ログイン
スクレイプで、まずログイン画面ですが、GoogleのreCAPTCHAが使用されています。普段アクセスしているIPでないものがアクセスすると、質問に答えるよう言われます。
最初は、全てrequestsを使用して、どこかサーバーに置くことも考えていたのですが、自身のマシンを使うようSeleniumベースでやることにしました。そうすることで、reCAPTCHAは発動されず、普通にSeleniumでアカウントを入力する形で、管理画面に入ることが出来ました。
注文メニューの取得
注文メニューはレポートには入っておらず、支払いという画面からしか取得出来ません。そこで、注文メニューに関してはスクレイプして取得することにしました。
まず、支払い画面の通信先を見ると、注文履歴のUUIDを使用してデータを取って来ているのが、分かりました。なので、Seleniumでログインした状態で、以下のURLをGETしに行くことでデータの取り出しに成功しました。
https://restaurant.uber.com/portal/payments/order-details?orderUUID=[ここに注文履歴のUUIDが入る]
これは、URLにアクセスするだけみたいなもんなので、本当に簡単でした。
フィードバックレビューの取得
フィードバックはレポートからも取ることが出来るのですが、誰がそのフィードバックしたかというのは、分からず、これを取ることにしました。が、これが意外と面倒でした。
フィードバックレビューの画面は、詳細を見るボタンが付いていて、フィードバックの量を増やしていくことが出来るのですが、Seleniumでデータが取り難かったのです。
そこで、ここでも直接APIを叩くようにしました。注文メニューの取得ではGETすることだけだったので簡単だったのですが、フィードバックレビューではPOSTする必要があり、更にGraphQLということで、ちょっと厄介でした。
実装方法としては、以下の通り、Seleniumで取得したcookieをrequestsに受け渡し、json形式でGraphQLのAPIを叩くというような方法です。また、headerもちゃんとセットしないと通りませんでした。
headers = { 'content-type': 'application/json', 'dnt': '1', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-origin', 'x-csrf-token': 'x', 'origin': 'https://restaurant.uber.com', 'referer': 'https://restaurant.uber.com/v2/home/[店舗ID]/feedback/reviews' } payload = {'operationName': 'EaterReviews', 'variables': { 'restaurantUUIDs': store_ids, 'lastTimestamp': ['%Y-%m-%dT%H:%M:%S%z'], 'filters': {'starRating': [1, 2, 3, 4, 5, -1]}, 'limit': 50 }, 'query': 'query EaterReviews($restaurantUUIDs: [ID!]!, $limit: Int, $lastTimestamp: String, $filters: EaterReviewFilterInput) {eaterReviews(restaurantUUIDs: $restaurantUUIDs, limit: $limit, lastTimestamp: $lastTimestamp, filters: $filters) {uuid timestamp rating comment tags menuItemReviews {id rating comment tags __typename} eater {uuid name profileURL __typename} eaterTotalOrders order {workflowUUID deliveredAt orderTotal currencyCode restaurant {uuid name __typename} __typename} reply {uuid promotion {uuid flatValue __typename} __typename} __typename}}' } session = requests.session() for cookie in driver.get_cookies(): session.cookies.set(cookie['name'], cookie['value']) res = session.post('https://restaurant.uber.com/v2/graphql', headers=headers, json=payload)
これでユーザーIDまで取れるので、ユーザーを一意にすることが出来ました。それにより、フィードバックをくれたユーザーに関しては、他店舗も合わせてリピートが分かるようにもなりました。
レポートと合わせて、結構良いデータを蓄積出来るようになりました。
もし、UberEatsを利用している店舗で、データの分析を行いたいなどの要望がありましたら、是非お問い合わせください。