2

Beatbox を使用して、SalesForce レポートを Pandas DataFrame に解析しようとした人はいますか? SOにはいくつかの例がありますが、それらのいずれも包括的なソリューションを提供していないか、少なくとも私が認識しているものは提供していません。

#!/usr/bin/env python3

import beatbox
import pandas as pd


sf = beatbox._tPartnerNS
service = beatbox.Client()
service.serverUrl = 'https://login.salesforce.com/services/Soap/u/38.0'
service.login('my-username', 'my-password')

report_id = '00myreport4G3V'

query = "SELECT Name FROM Report where id = '{}'".format(report_id)
query_result = service.query(query)

これは名前を選択するだけですが、理想的にはレポートの内容を DataFrame にロードしたいと考えています。何か助けてください。

4

2 に答える 2

1

レポート データは、Salesforce レポートおよびダッシュボード REST APIで取得できます。これは、Summer'15 (ver 34.0) 以降の Salesforce で機能します。

REST API のため、パッケージSimple-salesforceで例を書きました。(ただし、simple-salesforce を使用せずに書き直して、Beatbox の API セッションを使用し、少なくとも約 10 行のコードを追加して、要求パッケージのみをインストールすることは可能です。)

ユニバーサルコード

from collections import OrderedDict
from simple_salesforce import Salesforce
import pandas as pd
import json

class SfReportsApi(Salesforce):
    def __init__(self, *args, **kwargs):
        super(SfReportsApi, self).__init__(*args, **kwargs)

    def describe_report(self, report_id):
        return self._call_report(report_id, command='/describe')

    def to_pandas_dataframe(self, report_id, metadata=None):
        """SF report details exported to DataFrame, can be modified by metadata"""
        resp = self._call_report(report_id, metadata=metadata)
        if not resp['allData']:
            print("Detailed data have been truncated to the usual report limit (2000).")
        columns = []
        converters = []
        get_label = lambda x: x['label']
        sf_pandas_map = {
            'boolean': lambda x: x['value'],
            'currency': lambda x: x['value']['amount'],
            'date': lambda x: pd.Timestamp(x['value']),
            'datetime': lambda x: pd.Timestamp(x['value']),
            'double': lambda x: x['value'],
            'picklist': get_label,
            'string': get_label,
            'textarea': get_label,
        }
        for col in resp['reportExtendedMetadata']['detailColumnInfo'].values():
            columns.append(col['label'])
            converters.append(sf_pandas_map.get(col['dataType'], get_label))
        data = [[conv(cell) for conv, cell in zip(converters, row['dataCells'])]
                for sect_key, section in resp['factMap'].items()
                    if sect_key != 'T!T'
                        for row in section['rows']
                ]
        df = pd.DataFrame(data, columns=columns)
        return df

    def _call_report(self, report_id, metadata=None, command=None):
        url = '{}analytics/reports/{}{}'.format(self.base_url, report_id, command or '')
        data = json.dumps({'reportMetadata': metadata}) if metadata else None
        resp = self._call_salesforce('POST' if metadata else 'GET', url, data=data)
        return resp.json(object_pairs_hook=OrderedDict)

使用例

report_id = '00O24000004qtI4EAI'
# set Salesforce session_id some way (by login or reused from other app)
sf = SfReportsApi(username='me@example.com', password='password', security_token='token')
# sf = SfReportsApi(instance_url='https://na1.salesforce.com', session_id='')
# get report metadata if useful
metadata = sf.describe_report(report_id)['reportMetadata']
# modify them or write only the modified keys, e.g. change filters or remove subtotals etc.
metadata = {
    'orderBy': ['ACCOUNT.NAME'],
    'reportFilters': [{'value': 'W', 'column': 'ACCOUNT.NAME', 'operator': greaterOrEqual'}]
}
df = sf.to_pandas_dataframe(report_id, metadata)

列、フィルター、並べ替えなどを動的に追加することができます (レポートの同期実行に関するドキュメント)。この方法to_pandas_dataframeは、詳細を含む通常の表形式のレポート用であり、オプションで 1 つの総計と複数レベルの小計を使用できます。より複雑なレポートからデータを取得することは可能かもしれません ( Decode the Fact Mapまたはチートシートに関するドキュメントを参照)。

レポートできる詳細データ行は 2000 行のみです。フィルターを使用したいくつかの要求を使用して、すべてのデータを表示できます。

于 2017-08-11T23:41:27.430 に答える