DKM
DKM

Reputation: 1802

Pull Adwords Report for multiple mcc account

I'm looking for a way to pull reports for multiple mcc_account in one go using AdWords API for python, by below code I'm able to pass one MCC account at a time using google_ads.YAML file.

Is there a way to pass a multiple MCC accounts from CSV or text file and pull reports for them?

YAML file

# AdWordsClient configurations
adwords:
    #############################################################################
    # Required Fields                                                           #
    #############################################################################
    developer_token: XXXXXX
    #############################################################################
    # Optional Fields                                                           #
    #############################################################################
    client_customer_id: XXXX
    user_agent: XXXX
    # partial_failure: True
    # validate_only: True
    #############################################################################
    # OAuth2 Configuration                                                      #
    # Below you may provide credentials for either the installed application or #
    # service account flows. Remove or comment the lines for the flow you're    #
    # not using.                                                                #
    #############################################################################
    # The following values configure the client for the installed application
    # flow.
    client_id: XXXXX
    client_secret: XXXX
    refresh_token: XXXXX

Code

import multiprocessing
import os
from Queue import Empty
import time

import googleads.adwords
import googleads.errors

# Timeout between retries in seconds.
BACKOFF_FACTOR = 5
# Maximum number of processes to spawn.
MAX_PROCESSES = multiprocessing.cpu_count()
# Maximum number of retries for 500 errors.
MAX_RETRIES = 5
# Maximum number of items to be sent in a single API response.
PAGE_SIZE = 100
# Directory to download the reports to.
REPORT_DOWNLOAD_DIRECTORY = '.'


def _DownloadReport(process_id, report_download_directory, customer_id,
                    report_definition):
    report_downloader = (googleads.adwords.AdWordsClient.LoadFromStorage('                                                                      'googleads.yaml')
                            .GetReportDownloader())

    filepath = os.path.join(report_download_directory,
                            'adgroup_%d.csv' % customer_id)
    retry_count = 0

    while True:
        print ('[%d/%d] Loading report for customer ID "%s" into "%s"...'
                % (process_id, retry_count, customer_id, filepath))
        try:
            with open(filepath, 'wb') as handler:
                report_downloader.DownloadReport(
                    report_definition, output=handler,
                    client_customer_id=customer_id)
            return True, {'customerId': customer_id}
        except googleads.errors.AdWordsReportError as e:
            if e.code == 500 and retry_count < MAX_RETRIES:
                time.sleep(retry_count * BACKOFF_FACTOR)
            else:
                print ('Report failed for customer ID "%s" with code "%d" after "%d" '
                        'retries.' % (customer_id, e.code, retry_count + 1))
                return (False, {'customerId': customer_id, 'code': e.code,
                                'message': e.message})


class ReportWorker(multiprocessing.Process):
    """A worker Process used to download reports for a set of customer IDs."""

    def __init__(self, report_download_directory, report_definition,
                    input_queue, success_queue, failure_queue):
        """Initializes a ReportWorker.

        Args:
            report_download_directory: A string indicating the directory where you
            would like to download the reports.
            report_definition: A dict containing the report definition that you would
            like to run against all customer IDs in the input_queue.
            input_queue: A Queue instance containing all of the customer IDs that
            the report_definition will be run against.
            success_queue: A Queue instance that the details of successful report
            downloads will be saved to.
            failure_queue: A Queue instance that the details of failed report
            downloads will be saved to.
        """
        super(ReportWorker, self).__init__()
        self.report_download_directory = report_download_directory
        self.report_definition = report_definition
        self.input_queue = input_queue
        self.success_queue = success_queue
        self.failure_queue = failure_queue

    def run(self):
        while True:
            try:
                customer_id = self.input_queue.get(timeout=0.01)
            except Empty:
                break
            result = _DownloadReport(self.ident, self.report_download_directory,
                                        customer_id, self.report_definition)
            (self.success_queue if result[0] else self.failure_queue).put(result[1])


def GetCustomerIDs(client):
    """Retrieves all CustomerIds in the account hierarchy.

    Note that your configuration file must specify a client_customer_id belonging
    to an AdWords manager account.

    Args:
        client: an AdWordsClient instance.
    Raises:
        Exception: if no CustomerIds could be found.
    Returns:
        A Queue instance containing all CustomerIds in the account hierarchy.
    """
    # For this example, we will use ManagedCustomerService to get all IDs in
    # hierarchy that do not belong to MCC accounts.
    managed_customer_service = client.GetService('ManagedCustomerService',
                                                    version='v201809')

    offset = 0

    # Get the account hierarchy for this account.
    selector = {
        'fields': ['CustomerId'],
        'predicates': [{
            'field': 'CanManageClients',
            'operator': 'EQUALS',
            'values': [False]
        }],
        'paging': {
            'startIndex': str(offset),
            'numberResults': str(PAGE_SIZE)
        }
    }

    # Using Queue to balance load between processes.
    queue = multiprocessing.Queue()
    more_pages = True

    while more_pages:
        page = managed_customer_service.get(selector)

        if page and 'entries' in page and page['entries']:
            for entry in page['entries']:
                queue.put(entry['customerId'])
        else:
            raise Exception('Can\'t retrieve any customer ID.')
        offset += PAGE_SIZE
        selector['paging']['startIndex'] = str(offset)
        more_pages = offset < int(page['totalNumEntries'])

    return queue


def main(client, report_download_directory):
    # Determine list of customer IDs to retrieve report for.
    input_queue = GetCustomerIDs(client)
    reports_succeeded = multiprocessing.Queue()
    reports_failed = multiprocessing.Queue()

    # Create report definition.
    report_definition = {
        'reportName': 'Custom ADGROUP_PERFORMANCE_REPORT',
        'dateRangeType': 'LAST_7_DAYS',
        'reportType': 'ADGROUP_PERFORMANCE_REPORT',
        'downloadFormat': 'CSV',
        'selector': {
            'fields': ['CampaignId', 'AdGroupId', 'Impressions', 'Clicks',
                        'Cost'],
            # Predicates are optional.
            'predicates': {
                'field': 'AdGroupStatus',
                'operator': 'IN',
                'values': ['ENABLED', 'PAUSED']
            }
        },
    }

    queue_size = input_queue.qsize()
    num_processes = min(queue_size, MAX_PROCESSES)
    print 'Retrieving %d reports with %d processes:' % (queue_size, num_processes)

    # Start all the processes.
    processes = [ReportWorker(report_download_directory,
                                report_definition, input_queue, reports_succeeded,
                                reports_failed)
                    for _ in range(num_processes)]

    for process in processes:
        process.start()

    for process in processes:
        process.join()

    print 'Finished downloading reports with the following results:'
    while True:
        try:
            success = reports_succeeded.get(timeout=0.01)
        except Empty:
            break
        print '\tReport for CustomerId "%d" succeeded.' % success['customerId']

    while True:
        try:
            failure = reports_failed.get(timeout=0.01)
        except Empty:
            break
        print ('\tReport for CustomerId "%d" failed with error code "%s" and '
                'message: %s.' % (failure['customerId'], failure['code'],
                                    failure['message']))


if __name__ == '__main__':
    adwords_client = googleads.adwords.AdWordsClient.LoadFromStorage(
        'googleads.yaml')
    main(adwords_client, REPORT_DOWNLOAD_DIRECTORY)

How can I get the performance reports for multiple MCC accounts?

Upvotes: 0

Views: 614

Answers (1)

Vivek
Vivek

Reputation: 1523

You need to create different googleads.adwords.AdWordsClient instance for achieving the same as one client can only work with one adwords account (mcc or single account).

To create AdWordsClient instance, you can automate the flow without using YAML file for configuration and use below code to create the same (rest code will remain the same) -

"""Initializes a AdManagerClient without using yaml-cached credentials.
While our LoadFromStorage method provides a useful shortcut to instantiate a
client if you regularly use just one set of credentials, production applications
may need to swap out users. This example shows you how to create an OAuth2
client and a AdManagerClient without relying on a yaml file.
"""


from googleads import ad_manager
from googleads import oauth2

# OAuth2 credential information. In a real application, you'd probably be
# pulling these values from a credential storage.
CLIENT_ID = 'INSERT_CLIENT_ID_HERE'
CLIENT_SECRET = 'INSERT_CLIENT_SECRET_HERE'
REFRESH_TOKEN = 'INSERT_REFRESH_TOKEN_HERE'

# Ad Manager API information.
APPLICATION_NAME = 'INSERT_APPLICATION_NAME_HERE'

# Client customer id
CLIENT_CUSTOMER_ID = 'INSERT_CLIENT_CUSTOMER_ID_HERE'

def main(client_id, client_secret, refresh_token, application_name):
  oauth2_client = oauth2.GoogleRefreshTokenClient(
      client_id, client_secret, refresh_token)

  ad_manager_client = ad_manager.AdManagerClient(
      oauth2_client, application_name,client_customer_id=CLIENT_CUSTOMER_ID)

  networks = ad_manager_client.GetService('NetworkService').getAllNetworks()
  for network in networks:
    print ('Network with network code "%s" and display name "%s" was found.'
           % (network['networkCode'], network['displayName']))


if __name__ == '__main__':
  main(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN, APPLICATION_NAME)

Code reference

Upvotes: 1

Related Questions