From d71a832c0c67e1d6916db0796f83aefa913fdd0e Mon Sep 17 00:00:00 2001 From: Andrei Markin Date: Wed, 18 Feb 2026 18:02:39 +0400 Subject: [PATCH] showcase garf usage --- api_examples/ai_max_reports.py | 293 ++++++++++------------------ api_examples/list_pmax_campaigns.py | 79 +++----- 2 files changed, 123 insertions(+), 249 deletions(-) diff --git a/api_examples/ai_max_reports.py b/api_examples/ai_max_reports.py index 45d52a4..7d977ae 100644 --- a/api_examples/ai_max_reports.py +++ b/api_examples/ai_max_reports.py @@ -15,211 +15,120 @@ """This example gets AI Max performance reports.""" import argparse -import csv -from datetime import datetime, timedelta import sys -from typing import List, TYPE_CHECKING -from google.ads.googleads.errors import GoogleAdsException +from garf.community.google.ads import GoogleAdsApiReportFetcher +from garf.community.google.ads.api_clients import GoogleAdsApiClient +from garf.io.writers.csv_writer import CsvWriter +from google.ads.googleads.client import GoogleAdsClient + +campaign_details = """ +SELECT + campaign.id AS Campaign Id, + campaign.name AS Campaign Name, + expanded_landing_page_view.expanded_final_url AS Expanded Landing Page URL, + campaign.ai_max_setting.enable_ai_max AS AI Max Enabled +FROM + expanded_landing_page_view +WHERE + campaign.ai_max_setting.enable_ai_max = TRUE +ORDER BY + campaign.id +""" + +landing_page_matches = """ +SELECT + campaign.id AS Campaign ID, + campaign.name AS Campaign Name, + expanded_landing_page_view.expanded_final_url AS Expanded Landing Page URL, + campaign.ai_max_setting.enable_ai_max AS AI Max Enabled +FROM + expanded_landing_page_view +WHERE + campaign.ai_max_setting.enable_ai_max = TRUE +ORDER BY + campaign.id +""" + +search_terms = """ +SELECT + campaign.id AS Campaign ID, + campaign.name AS Campaign Name, + ai_max_search_term_ad_combination_view.search_term AS Search Term, + metrics.impressions AS Impressions, + metrics.clicks AS Clicks, + metrics.cost_micros / 1e6 AS Cost, + metrics.conversions AS Conversions +FROM + ai_max_search_term_ad_combination_view +WHERE + segments.date BETWEEN '{start_date}' AND '{end_date}' +ORDER BY + metrics.impressions DESC +""" -if TYPE_CHECKING: - from google.ads.googleads.client import GoogleAdsClient - from google.ads.googleads.v22.services.types.google_ads_service import ( - SearchGoogleAdsStreamResponse, - ) +def main(client: "GoogleAdsClient", customer_id: str, report_type: str) -> None: + """The main method that creates all necessary entities for the example. -def _write_to_csv( - file_path: str, - headers: List[str], - response: "SearchGoogleAdsStreamResponse", -) -> None: - """Writes the given response to a CSV file. - - Args: - file_path: The path to the CSV file to write to. - headers: The headers for the CSV file. - response: The response from the Google Ads API. - """ - with open(file_path, "w", newline="", encoding="utf-8") as csvfile: - csv_writer = csv.writer(csvfile) - csv_writer.writerow(headers) - - for batch in response: - for row in batch.results: - csv_writer.writerow(list(row)) - - print(f"Report written to {file_path}") - - -def get_campaign_details(client: "GoogleAdsClient", customer_id: str) -> None: - """Gets AI Max campaign details and writes them to a CSV file. - - Args: - client: An initialized GoogleAdsClient instance. - customer_id: The client customer ID. - """ - ga_service = client.get_service("GoogleAdsService") - - query = """ - SELECT - campaign.id, - campaign.name, - expanded_landing_page_view.expanded_final_url, - campaign.ai_max_setting.enable_ai_max - FROM - expanded_landing_page_view - WHERE - campaign.ai_max_setting.enable_ai_max = TRUE - ORDER BY - campaign.id""" - - response = ga_service.search_stream(customer_id=customer_id, query=query) - - _write_to_csv( - "saved_csv/ai_max_campaign_details.csv", - [ - "Campaign ID", - "Campaign Name", - "Expanded Landing Page URL", - "AI Max Enabled", - ], - response, - ) - - -def get_landing_page_matches( - client: "GoogleAdsClient", customer_id: str -) -> None: - """Gets AI Max landing page matches and writes them to a CSV file. - - Args: - client: An initialized GoogleAdsClient instance. - customer_id: The client customer ID. - """ - ga_service = client.get_service("GoogleAdsService") - - query = """ - SELECT - campaign.id, - campaign.name, - expanded_landing_page_view.expanded_final_url - FROM - expanded_landing_page_view - WHERE - campaign.ai_max_setting.enable_ai_max = TRUE - ORDER BY - campaign.id""" - - response = ga_service.search_stream(customer_id=customer_id, query=query) - - _write_to_csv( - "saved_csv/ai_max_landing_page_matches.csv", - ["Campaign ID", "Campaign Name", "Expanded Landing Page URL"], - response, - ) - - -def get_search_terms(client: "GoogleAdsClient", customer_id: str) -> None: - """Gets AI Max search terms and writes them to a CSV file. - - Args: - client: An initialized GoogleAdsClient instance. - customer_id: The client customer ID. - """ - ga_service = client.get_service("GoogleAdsService") - - end_date = datetime.now() - start_date = end_date - timedelta(days=30) - - gaql_query = f""" - SELECT - campaign.id, - campaign.name, - ai_max_search_term_ad_combination_view.search_term, - metrics.impressions, - metrics.clicks, - metrics.cost_micros, - metrics.conversions - FROM - ai_max_search_term_ad_combination_view - WHERE - segments.date BETWEEN '{start_date.strftime("%Y-%m-%d")}' AND '{end_date.strftime("%Y-%m-%d")}' - ORDER BY - metrics.impressions DESC + Args: + client: an initialized GoogleAdsClient instance. + customer_id: a client customer ID. + report_type: the type of report to generate. """ + csv_writer = CsvWriter(destination_folder="saved_csv") + api_client = GoogleAdsApiClient.from_googleads_client(client) + fetcher = GoogleAdsApiReportFetcher(api_client=api_client) - stream = ga_service.search_stream(customer_id=customer_id, query=gaql_query) - - _write_to_csv( - "saved_csv/ai_max_search_terms.csv", - [ - "Campaign ID", - "Campaign Name", - "Search Term", - "Impressions", - "Clicks", - "Cost (micros)", - "Conversions", - ], - stream, - ) - - -def main(client: "GoogleAdsClient", customer_id: str, report_type: str) -> None: - """The main method that creates all necessary entities for the example. - - Args: - client: an initialized GoogleAdsClient instance. - customer_id: a client customer ID. - report_type: the type of report to generate. - """ - try: if report_type == "campaign_details": - get_campaign_details(client, customer_id) + report = fetcher.fetch( + campaign_details, title=report_type, account=customer_id + ) elif report_type == "landing_page_matches": - get_landing_page_matches(client, customer_id) + report = fetcher.fetch( + landing_page_matches, title=report_type, account=customer_id + ) elif report_type == "search_terms": - get_search_terms(client, customer_id) + report = fetcher.fetch( + search_terms, + title=report_type, + account=customer_id, + args={ + "macro": { + "start_date": ":YYYYMMDD-30", + "end_date": ":YYYYMMDD-1", + } + }, + ) else: - print(f"Unknown report type: {report_type}") - sys.exit(1) - except GoogleAdsException as ex: - print( - f"Request with ID '{ex.request_id}' failed with status " - f"'{ex.error.code.name}' and includes the following errors:" - ) - for error in ex.failure.errors: - print(f"\tError with message '{error.message}'.") - if error.location: - for field_path_element in error.location.field_path_elements: - print(f"\t\tOn field: {field_path_element.field_name}") - sys.exit(1) + print(f"Unknown report type: {report_type}") + sys.exit(1) + csv_writer.write(report, report_type) if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Fetches AI Max performance data." - ) - parser.add_argument( - "-c", - "--customer_id", - type=str, - required=True, - help="The Google Ads customer ID.", - ) - parser.add_argument( - "-r", - "--report_type", - type=str, - required=True, - choices=["campaign_details", "landing_page_matches", "search_terms"], - help="The type of report to generate.", - ) - args = parser.parse_args() + parser = argparse.ArgumentParser( + description="Fetches AI Max performance data." + ) + parser.add_argument( + "-c", + "--customer_id", + type=str, + required=True, + help="The Google Ads customer ID.", + ) + parser.add_argument( + "-r", + "--report_type", + type=str, + required=True, + choices=["campaign_details", "landing_page_matches", "search_terms"], + help="The type of report to generate.", + ) + args = parser.parse_args() - # GoogleAdsClient will read the google-ads.yaml configuration file in the - # home directory if none is specified. - googleads_client = GoogleAdsClient.load_from_storage(version="v23") + # GoogleAdsClient will read the google-ads.yaml configuration file in the + # home directory if none is specified. + googleads_client = GoogleAdsClient.load_from_storage(version="v23") - main(googleads_client, args.customer_id, args.report_type) + main(googleads_client, args.customer_id, args.report_type) diff --git a/api_examples/list_pmax_campaigns.py b/api_examples/list_pmax_campaigns.py index 01e64d6..9f1f69b 100644 --- a/api_examples/list_pmax_campaigns.py +++ b/api_examples/list_pmax_campaigns.py @@ -18,59 +18,30 @@ """ import argparse -import sys +from garf.community.google.ads import GoogleAdsApiReportFetcher +from garf.community.google.ads.api_clients import GoogleAdsApiClient +from garf.io.writers.console_writer import ConsoleWriter from google.ads.googleads.client import GoogleAdsClient -from google.ads.googleads.errors import GoogleAdsException - - -def main(client: "GoogleAdsClient", customer_id: str) -> None: - """The main method that creates all necessary entities for the example. - - Args: - client: an initialized GoogleAdsClient instance. - customer_id: a client customer ID. - """ - ga_service = client.get_service("GoogleAdsService") - - query = """ - SELECT - campaign.name, - campaign.advertising_channel_type - FROM - campaign - WHERE - campaign.advertising_channel_type = 'PERFORMANCE_MAX'""" - - # Issues a search request using streaming. - response = ga_service.search_stream(customer_id=customer_id, query=query) - - try: - for batch in response: - for row in batch.results: - print( - f'Campaign with name "{row.campaign.name}" ' - f"is a {row.campaign.advertising_channel_type.name} campaign." - ) - except GoogleAdsException as ex: - print( - f"Request with ID '{ex.request_id}' failed with status " - f"'{ex.error.code().name}' and includes the following errors:" - ) - for error in ex.failure.errors: - print(f"\tError with message '{error.message}'.") - if error.location: - for field_path_element in error.location.field_path_elements: - print(f"\t\tOn field: '{field_path_element.field_name}'") - sys.exit(1) +query = """ +SELECT + campaign.name AS Campaign Name, + campaign.advertising_channel_type AS Campaign Type +FROM + campaign +WHERE + campaign.advertising_channel_type = PERFORMANCE_MAX +""" if __name__ == "__main__": # GoogleAdsClient will read the google-ads.yaml configuration file in the # home directory if none is specified. googleads_client = GoogleAdsClient.load_from_storage(version="v23") - parser = argparse.ArgumentParser(description="Lists Performance Max campaigns.") + parser = argparse.ArgumentParser( + description="Lists Performance Max campaigns." + ) # The following argument(s) are required to run the example. parser.add_argument( "-c", @@ -81,16 +52,10 @@ def main(client: "GoogleAdsClient", customer_id: str) -> None: ) args = parser.parse_args() - try: - main(googleads_client, args.customer_id) - except GoogleAdsException as ex: - print( - f"Request with ID '{ex.request_id}' failed with status " - f"'{ex.error.code().name}' and includes the following errors:" - ) - for error in ex.failure.errors: - print(f"\tError with message '{error.message}'.") - if error.location: - for field_path_element in error.location.field_path_elements: - print(f"\t\tOn field: '{field_path_element.field_name}'") - sys.exit(1) + console_writer = ConsoleWriter() + api_client = GoogleAdsApiClient.from_googleads_client(googleads_client) + fetcher = GoogleAdsApiReportFetcher(api_client=api_client) + + report = fetcher.fetch(query, account=args.customer_id) + + console_writer.write(report, "pmax_campaigns")