Life is Like a Boat

忘備録や経済、投資、プログラミングに関するメモやtipsなど

PythonからMicrosoft Dataverseに直接アクセスする方法

MicrosoftのPower PlatformにはPower BIというBIツールがあります。解説本やチュートリアルも豊富に出ていて、株クラのPowerBIマスターの方が以前に株価データ配信のKabuPlusと組み合わせたPowerBIダッシュボードを作成されていて(https://twitter.com/yustock)、アイデア次第でなんでも表現できるな〜と思った次第です。

ただ、すでにPythonを使った分析基盤がある場合にわざわざPower BIの使い方を学んでPython側で溜まった知見の移行をする。。。というのは手が出づらいものです。

それぞれに良さがあり、活用シーンが異なります。すでにPandas+Jupyter資産があり、アドホックな分析をやりたい場合には慣れている方を使った方が良いでしょう。

ここでは、Power PlatformのDataverseに顧客データや営業データが既に溜まっていて、Pandas+Jupyter Notebookを使ってデータ分析するケースを考えたいと思います。

方法その1

一番手軽なやり方は、Power Automateの"When a HTTP request is received"トリガーを使うことです。

数ステップを組み合わせたこちらのPower Automate フローで取引先テーブルを全部返すGETメソッドのエンドポイントができてしまいます。一度のリクエストで最大5000行という制限がありますが、@odata.nextLinkで次の5000件が取れそうな感じなので(検証してません)、回避する方法はググれば探せると思います。

エンドポイントにアクセスしてレスポンスをDataframeにすることができます。 f:id:nerimplo:20211110115209p:plain

方法その2

方法2はOdataプロトコルとRestful APIを使ってDataverseのレコードを取得する方法です。

スクショ付きで説明したいと思います。

まず、Azure Active DirectoryでAppを登録します。ここで言うAppはOAuth認証を使用してDataverse環境に接続できるアプリケーションです。 f:id:nerimplo:20211115162429p:plain

Appによろしく名前をつけて、Single Tenantを選び次へ。 f:id:nerimplo:20211115162507p:plain

client secretを作ります。この値は後で使うので必ずコピーします。値が表示されるのは作成時のみなので、ここでコピーしないとまた作り直す必要があります。 f:id:nerimplo:20211115162602p:plain

Power Platform admin centerに移動します。設定からアプリケーションユーザーを作成します。 f:id:nerimplo:20211115162648p:plain

Appユーザの追加ボタンを押し、右パネルから先程Azure ADで作ったApp名を選び追加します。 f:id:nerimplo:20211115162831p:plain

この後、セキュリティロールをアサインする必要があるのですが、App用に個別のロールを作り、適切な権限を与えることを強く推奨します。特にデータ分析だけに使うのであればRead権限だけで十分なはずです。

ここまでで下準備は完了です。

あとはアクセストークンを取得して、取引先レコードを取得するためのDataverse Web APIのエンドポイントに対してリクエストするだけです。以下サンプルコードです。

import requests
import pandas as pd

LOGIN_URL = 'https://login.microsoftonline.com/{0}/oauth2/token'
TENANT_ID = 'YOUR_TENANT_ID'
APP_ID = 'YOUR_APP_ID'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'
GRANT_TYPE = 'client_credentials'
RESOURCE = 'https://YOUR_ENV.crm7.dynamics.com/'
DATAVERSE_DATA_URL = '{0}/api/data/v9.1/'.format(RESOURCE)

response = requests.post(LOGIN_URL.format(TENANT_ID), data = {
    'tenant_id': TENANT_ID,
    'client_id': APP_ID,
    'client_secret': CLIENT_SECRET,
    'grant_type': GRANT_TYPE,
    'resource': RESOURCE
})

access_token = response.json().get('access_token')
token_type = response.json().get('token_type')

ACCOUNTS_DATA_URL = f'{DATAVERSE_DATA_URL}accounts'
accounts = requests.get(ACCOUNTS_DATA_URL, headers = {'Authorization': f'{token_type} {access_token}'})

df = pd.DataFrame(accounts.json().get('value'))

解説するポイントとしては、取引先レコードを取得するエンドポイントACCOUNTS_DATA_URLの最後が/accountsと複数形になっている点くらいです。これ結構ハマりポイントだと思いますw https://xxxxx.dynamics.com/api/data/v9.1/accounts

レスポンスに含まれるDataverseレコードはJSON形式になっていますので、これをPandasのDataframeにしてあげればあとはこっちのものです。

さらにOdataプロトコルを使うことでアドホックなクエリを作ることができます。

/accounts?$filter=Name eq 'ABC CORP'

とすると取引先名がABC CORPという会社のレコードを取得することができます。

ちなみにSQL脳の人がODataプロトコルのクエリを作る際にこのチートシートがめちゃくちゃ役立ちますw ぜひ使ってみてください。

skyvia.com