1

I am trying to follow this tutorial to so connect to Google Analytics API. I followed everything step by step. But when I run the module in python, I get the following error:

Traceback (most recent call last):
  File "C:\Users\me\Desktop\New folder (3)\HelloAnalytics.py", line 112, in <module>
    main()
  File "C:\Users\me\Desktop\New folder (3)\HelloAnalytics.py", line 106, in main
    service_account_email)
  File "C:\Users\me\Desktop\New folder (3)\HelloAnalytics.py", line 35, in get_service
    service_account_email, key, scopes=scope)
  File "C:\Python27\lib\site-packages\oauth2client\service_account.py", line 274, in from_p12_keyfile
    with open(filename, 'rb') as file_obj:
TypeError: file() argument 1 must be encoded string without NULL bytes, not str

If anyone can point me in the right direction, that would be great. The full code is right here:

"""A simple example of how to access the Google Analytics API."""

import argparse

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

import httplib2
from oauth2client import client
from oauth2client import file
from oauth2client import tools



def get_service(api_name, api_version, scope, key_file_location,
                service_account_email):
  """Get a service that communicates to a Google API.

  Args:
    api_name: The name of the api to connect to.
    api_version: The api version to connect to.
    scope: A list auth scopes to authorize for the application.
    key_file_location: The path to a valid service account p12 key file.
    service_account_email: The service account email address.

  Returns:
    A service that is connected to the specified API.
  """

  f = open(key_file_location, 'rb')
  key = f.read()
  f.close()

  credentials = ServiceAccountCredentials.from_p12_keyfile(
    service_account_email, key, scopes=scope)

  http = credentials.authorize(httplib2.Http())

  # Build the service object.
  service = build(api_name, api_version, http=http)

  return service


def get_first_profile_id(service):
  # Use the Analytics service object to get the first profile id.

  # Get a list of all Google Analytics accounts for this user
  accounts = service.management().accounts().list().execute()

  if accounts.get('items'):
    # Get the first Google Analytics account.
    account = accounts.get('items')[0].get('id')

    # Get a list of all the properties for the first account.
    properties = service.management().webproperties().list(
        accountId=account).execute()

    if properties.get('items'):
      # Get the first property id.
      property = properties.get('items')[0].get('id')

      # Get a list of all views (profiles) for the first property.
      profiles = service.management().profiles().list(
          accountId=account,
          webPropertyId=property).execute()

      if profiles.get('items'):
        # return the first view (profile) id.
        return profiles.get('items')[0].get('id')

  return None


def get_results(service, profile_id):
  # Use the Analytics Service Object to query the Core Reporting API
  # for the number of sessions within the past seven days.
  return service.data().ga().get(
      ids='ga:' + profile_id,
      start_date='7daysAgo',
      end_date='today',
      metrics='ga:sessions').execute()


def print_results(results):
  # Print data nicely for the user.
  if results:
    print 'View (Profile): %s' % results.get('profileInfo').get('profileName')
    print 'Total Sessions: %s' % results.get('rows')[0][0]

  else:
    print 'No results found'


def main():
  # Define the auth scopes to request.
  scope = ['https://www.googleapis.com/auth/analytics.readonly']

  # Use the developer console and replace the values with your
  # service account email and relative location of your key file.
  service_account_email = '<Replace with your service account email address.>'
  key_file_location = '<Replace with /path/to/generated/client_secrets.p12>'

  # Authenticate and construct service.
  service = get_service('analytics', 'v3', scope, key_file_location,
    service_account_email)
  profile = get_first_profile_id(service)
  print_results(get_results(service, profile))


if __name__ == '__main__':
  main()
Jay
  • 21
  • 1
  • 4
  • 1
    This appears to be way more code than would be necessary to reproduce your error. Can you instead post a minimal sample of this code necessary to produce the error you've (helpfully!) provided? – BlackVegetable Mar 04 '16 at 21:39
  • @BlackVegetable Honestly, I am quite new to this. I would not even know what to take out without breaking something else. My apologies. – Jay Mar 04 '16 at 22:52
  • Did you use a proper filepath (with a named drive letter, since apparently you are on windows) for the key_file_location ? The error message seems to complain about the argument for the file operation, not anything that is inside the file. – Eike Pierstorff Mar 05 '16 at 08:26
  • @EikePierstorff Thanks for the reply. In the code, I use: key_file_location = './client_secrets.p12', and I run the code in the same folder. But I get the same, exact error, when I use the full path with the drive letter. I know that i have the path correct and the p12 file is being read because when I switch the path, I get an 'No such file or directory:' error. Thanks for the help. – Jay Mar 07 '16 at 08:14

3 Answers3

2

The error is being traced back to the ServiceAccountCredentials.from_p12_keyfile() function. It seems to be detecting a null value in the service_account_email string. you could make it a raw string by putting an 'r' before the first quote:

service_account_email = r'<Replace with your service account email address.>'

or by using a backslash '\' to escape the null value.

Zulan
  • 20,904
  • 6
  • 41
  • 90
Anders Elmgren
  • 551
  • 4
  • 8
  • Thanks for looking into this. Pardon my ignorance but I am not sure what null value it could be referring to. So I tried your suggestion with service_account_email = r'my_app@generated_email_address.gserviceaccount.com' but I still get the same exact error. Any other ideas would be appreciated. – Jay Mar 04 '16 at 22:57
  • Did you follow all the steps here: https://developers.google.com/analytics/devguides/reporting/core/v3/quickstart/service-py#clientId? The generated service account should have the structure "-@developer.gserviceaccount.com". – Anders Elmgren Mar 04 '16 at 23:13
  • Thanks again for the help. I do follow all of the steps and I get the email address that looks like @ultra-glyph-.iam.gserviceaccount.com. The naming does not look exactly like the instructions, but according to [here](http://stackoverflow.com/questions/33990854/cant-find-developer-gserviceaccount-for-gmail), Google replaced their naming of the service accounts and the client IDs. – Jay Mar 04 '16 at 23:45
1

I ran into this problem yesterday. The problem is with the HelloAnalytics.py sample code. Replace the following three lines:

  f = open(key_file_location, 'rb')
  key = f.read()
  f.close()

with this instead:

  key = key_file_location

Unfortunately, the Google sample code tries to read the contents of the p12 file when it should just be pointing to the file location. The rest of the sample code ran fine for me without having to prefix my email or file location with r.

1

I had this same problem. I found it was the following line in the helloanalytics.py file. You need to modify line 33:

credentials = ServiceAccountCredentials.from_p12_keyfile(service_account_email, key, scopes=scope)

The ServiceAccountCredentials.from_p12_keyfile() function requires the key_file_location not the key.

Replace key with key_file_location:

credentials = ServiceAccountCredentials.from_p12_keyfile(service_account_email, key_file_location, scopes=scope)

Mathew
  • 11
  • 2
  • Thank you so much. This solved the problem. Your solution worked as wells as the answer from Pallas Horwitz. I appreciate the help. – Jay Mar 09 '16 at 16:18
  • No worries Jay, glad I could help. It was frustrating the heck out of me yesterday. Yea, Pallas answer also fixed the problem. I was just going to comment on her post, but apparently I don't have enough reputation points. – Mathew Mar 09 '16 at 21:55