YOGESH
YOGESH

Reputation: 63

Getting HttpError 401 while generating google Admob network report using python script

Below is the code that I am using to generate the Admob network report

from apiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
import os


base_path=os.path.dirname(os.path.realpath(__file__))
scopes=['https://www.googleapis.com/auth/admob.report']
key_file_location = base_path+'/config/service_account.json'

credentials = ServiceAccountCredentials.from_json_keyfile_name(key_file_location, scopes)



account_id='accounts/pub-XXXXXXXXXXXXXXXX'
network_report_filter = {
  'dateRange': {
    'startDate': {'year': 2020, 'month': 1, 'day': 1},
    'endDate': {'year': 2020, 'month': 2, 'day': 10}
  },
  'dimensions': ['DATE', 'APP', 'COUNTRY'],
  'metrics': ['CLICKS', 'ESTIMATED_EARNINGS'],
  'dimensionFilters': [
    {
      'dimension': 'COUNTRY',
      'matchesAny': {'values': [{'value': 'US', 'value': 'CN'}]}
    }
  ],
  'sortConditions': [
    {'dimension':'APP', 'order': 'ASCENDING'},
    {'metric':'CLICKS', 'order': 'DESCENDING'}
  ],
  'localizationSettings': {
    'currencyCode': 'USD',
    'languageCode': 'en-US'
  }
}


# Build the service object.
admob = build('admob', 'v1', credentials=credentials)

admob._resourceDesc=network_report_filter
accounts=admob.accounts()
network_report=accounts.networkReport().generate(parent=account_id)
data=network_report.execute()

It throws the below error

*** HttpError: https://admob.googleapis.com/v1/accounts/pub-XXXXXXXXXXXXXXXX/networkReport:generate?alt=json returned "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.">

I have generated the service account credentials with Admob API is enabled. But not able to figure out why there is authentication error.

Upvotes: 0

Views: 886

Answers (2)

BeanTong
BeanTong

Reputation: 1

Currently, google admob api does not support service accounts

for more details, see here enter link description here

Upvotes: 0

Maksym Prokhorenko
Maksym Prokhorenko

Reputation: 426

The main issue, that code above tries to use the service account to query the api. But, it's not supported. It could be queried with OAuth2.0 Client Id.

The steps to generate OAth2.0 Client ID:

The following works well for me:

Libs:

pip3 install --upgrade google-api-python-client --user
pip3 install --upgrade oauth2client --user

Code example:

import csv
import sys

from googleapiclient import discovery
from googleapiclient.http import build_http
from oauth2client import tools
from oauth2client.file import Storage
from oauth2client.client import OAuth2WebServerFlow


class AdMobAPI:

    def __init__(self):
        scope = 'https://www.googleapis.com/auth/admob.report'
        name = 'admob'
        version = 'v1'

        flow = OAuth2WebServerFlow(client_id='<todo: replace with a client_id from the secret json>',
                                   client_secret='<todo: replace with a secret from the secret json>',
                                   scope=scope)
        storage = Storage(name + '.dat')
        credentials = storage.get()
        if credentials is None or credentials.invalid:
            credentials = tools.run_flow(flow, storage)
        http = credentials.authorize(http=build_http())
        self.admob = discovery.build(name, version, http=http)

    # Convert to the list of dictionaries
    def report_to_list_of_dictionaries(self, response):
        result = []

        for report_line in response:
            if report_line.get('row'):
                print(report_line)
                row = report_line.get('row')
                dm = {}
                if row.get('dimensionValues'):
                    for key, value in row.get('dimensionValues').items():
                        if value.get('value') and value.get('displayLabel'):
                            dm.update({key: value.get('value')})
                            dm.update({key + '_NAME': value.get('displayLabel')})
                        else:
                            dm.update({key: next(filter(None, [value.get('value'), value.get('displayLabel')]))})
                if row.get('metricValues'):
                    for key, value in row.get('metricValues').items():
                        dm.update({key: next(filter(None, [value.get('value'), value.get('microsValue'), value.get('integerValue')]))})
                result.append(dm)
        return result

    def generate_report(self, publisher_id):
        date_range = {'startDate': {'year': 2020, 'month': 4, 'day': 1},
                      'endDate': {'year': 2020, 'month': 4, 'day': 1}}
        dimensions = ['DATE', 'APP', 'PLATFORM', 'COUNTRY']
        metrics = ['ESTIMATED_EARNINGS', 'IMPRESSIONS', 'CLICKS',
                   'AD_REQUESTS', 'MATCHED_REQUESTS']
        sort_conditions = {'dimension': 'DATE', 'order': 'DESCENDING'}
        report_spec = {'dateRange': date_range,
                       'dimensions': dimensions,
                       'metrics': metrics,
                       'sortConditions': [sort_conditions]}

        request = {'reportSpec': report_spec}
        return self.admob.accounts().networkReport().generate(
                parent='accounts/{}'.format(publisher_id),
                body=request).execute()

api = AdMobAPI()
raw_report = api.generate_report('<todo: replace with publisher id, smth like pub-[0-9]+>')
report_as_list_of_dictionaries = api.report_to_list_of_dictionaries(raw_report)

# Convert to CSV
dict_writer = csv.DictWriter(sys.stdout, report_as_list_of_dictionaries[0].keys())
dict_writer.writeheader()
dict_writer.writerows(report_as_list_of_dictionaries)

Upvotes: 1

Related Questions