├── .gitignore ├── README.md ├── config └── config.json ├── creds_example └── googleads.yaml ├── requirements.txt └── src ├── __init__.py ├── models └── utils.py └── test_google_ads_access └── download_keywords_from_account.py /.gitignore: -------------------------------------------------------------------------------- 1 | /creds 2 | /venv 3 | /src/creds 4 | .idea 5 | /.idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # google_ads_tutorials 2 | -------------------------------------------------------------------------------- /config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "test_account_id" : "7036865393" 3 | 4 | } -------------------------------------------------------------------------------- /creds_example/googleads.yaml: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # Required Fields # 3 | ############################################################################# 4 | developer_token: INSERT_HERE 5 | ############################################################################# 6 | # Optional Fields # 7 | ############################################################################# 8 | login_customer_id: INSERT_HERE 9 | # user_agent: INSERT_USER_AGENT_HERE 10 | # partial_failure: True 11 | validate_only: False 12 | ############################################################################# 13 | # OAuth2 Configuration # 14 | # Below you may provide credentials for either the installed application or # 15 | # service account flows. Remove or comment the lines for the flow you're # 16 | # not using. # 17 | ############################################################################# 18 | # The following values configure the client for the installed application 19 | # flow. 20 | client_id: INSERT_HERE 21 | client_secret: INSERT_HERE 22 | refresh_token: INSERT_HERE 23 | # The following values configure the client for the service account flow. 24 | # path_to_private_key_file: INSERT_PATH_TO_JSON_KEY_FILE_HERE 25 | # delegated_account: INSERT_DOMAIN_WIDE_DELEGATION_ACCOUNT 26 | ############################################################################# 27 | # ReportDownloader Headers # 28 | # Below you may specify boolean values for optional headers that will be # 29 | # applied to all requests made by the ReportDownloader utility by default. # 30 | ############################################################################# 31 | # report_downloader_headers: 32 | # skip_report_header: False 33 | # skip_column_header: False 34 | # skip_report_summary: False 35 | # use_raw_enum_values: False 36 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pandas 2 | googleads 3 | google-ads -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | 4 | # my local directory is right now 5 | src_path = os.path.dirname(os.path.realpath(__file__)) 6 | 7 | dir_path = os.path.join(src_path, '..') 8 | 9 | # credentials dictonary 10 | creds = {"google_ads": dir_path + "/creds/googleads.yaml"} 11 | 12 | 13 | if not os.path.isfile(creds["google_ads"]): 14 | raise FileExistsError("File doesn't exists. Please create folder src/creds and put googleads.yaml file there. ") 15 | 16 | resources = {"config": dir_path + "/config/config.json"} 17 | 18 | 19 | # This logging allows to see additional information on debugging 20 | import logging 21 | logging.basicConfig(level=logging.INFO, format='[%(asctime)s - %(levelname)s] %(message).5000s') 22 | logging.getLogger('google.ads.google_ads.client').setLevel(logging.INFO) 23 | 24 | 25 | # Initialize the google_ads client 26 | from google.ads.google_ads.client import GoogleAdsClient 27 | gads_client = GoogleAdsClient.load_from_storage(creds["google_ads"]) 28 | 29 | # Initialize all global configurations 30 | config = json.load(open(resources["config"], "r")) 31 | 32 | -------------------------------------------------------------------------------- /src/models/utils.py: -------------------------------------------------------------------------------- 1 | 2 | def get_account_id(account_id, check_only=False): 3 | """ 4 | Converts int to str, checks if str has dashes. Returns 10 chars str or raises error 5 | :check_only - if True, returns None instead of Error 6 | 7 | """ 8 | 9 | if isinstance(account_id, int) and len(str(account_id)) == 10: 10 | return str(account_id) 11 | if isinstance(account_id, str) and len(account_id.replace("-", "")) == 10: 12 | return account_id.replace("-", "") 13 | if check_only: 14 | return None 15 | raise ValueError(f"Couldn't recognize account id from {account_id}") 16 | 17 | 18 | def choose_account_id(account_id, test_account_id): 19 | """ 20 | Picks actual account id or a test one. Check both of the accounts ids first. 21 | Raises value if both are incorrect 22 | """ 23 | 24 | if not get_account_id(account_id, True) and not get_account_id(test_account_id, True): 25 | raise ValueError("Couldn't pick an account id ") 26 | return get_account_id(account_id, True) or get_account_id(test_account_id, True) 27 | 28 | 29 | def micros_to_currency(micros): 30 | return micros / 1000000.0 31 | 32 | -------------------------------------------------------------------------------- /src/test_google_ads_access/download_keywords_from_account.py: -------------------------------------------------------------------------------- 1 | from src import gads_client, config 2 | from src.models.utils import choose_account_id 3 | 4 | import sys 5 | from google.ads.google_ads.errors import GoogleAdsException 6 | 7 | # Put an account id to download stats from. Note: not MCC, no dash lines 8 | CUSTOMER_ID = "" 9 | 10 | 11 | def main(client, customer_id): 12 | ga_service = client.get_service("GoogleAdsService", version="v5") 13 | 14 | query = """ 15 | SELECT 16 | campaign.id, 17 | campaign.name, 18 | ad_group.id, 19 | ad_group.name, 20 | ad_group_criterion.criterion_id, 21 | ad_group_criterion.keyword.text, 22 | ad_group_criterion.keyword.match_type, 23 | metrics.impressions, 24 | metrics.clicks, 25 | metrics.cost_micros 26 | FROM keyword_view 27 | WHERE 28 | segments.date DURING LAST_7_DAYS 29 | AND campaign.advertising_channel_type = 'SEARCH' 30 | AND ad_group.status = 'ENABLED' 31 | AND ad_group_criterion.status IN ('ENABLED', 'PAUSED') 32 | ORDER BY metrics.impressions DESC 33 | LIMIT 50""" 34 | 35 | # Issues a search request using streaming. 36 | response = ga_service.search_stream(customer_id, query) 37 | keyword_match_type_enum = client.get_type( 38 | "KeywordMatchTypeEnum", version="v5" 39 | ).KeywordMatchType 40 | try: 41 | for batch in response: 42 | for row in batch.results: 43 | campaign = row.campaign 44 | ad_group = row.ad_group 45 | criterion = row.ad_group_criterion 46 | metrics = row.metrics 47 | keyword_match_type = keyword_match_type_enum.Name( 48 | criterion.keyword.match_type 49 | ) 50 | print( 51 | f'Keyword text "{criterion.keyword.text}" with ' 52 | f'match type "{keyword_match_type}" ' 53 | f"and ID {criterion.criterion_id} in " 54 | f'ad group "{ad_group.name}" ' 55 | f'with ID "{ad_group.id}" ' 56 | f'in campaign "{campaign.name}" ' 57 | f"with ID {campaign.id} " 58 | f"had {metrics.impressions} impression(s), " 59 | f"{metrics.clicks} click(s), and " 60 | f"{metrics.cost_micros} cost (in micros) during " 61 | "the last 7 days." 62 | ) 63 | except GoogleAdsException as ex: 64 | print( 65 | f'Request with ID "{ex.request_id}" failed with status ' 66 | f'"{ex.error.code().name}" and includes the following errors:' 67 | ) 68 | for error in ex.failure.errors: 69 | print(f'\tError with message "{error.message}".') 70 | if error.location: 71 | for field_path_element in error.location.field_path_elements: 72 | print(f"\t\tOn field: {field_path_element.field_name}") 73 | sys.exit(1) 74 | 75 | 76 | if __name__ == "__main__": 77 | id_to_load = choose_account_id(CUSTOMER_ID, config.get("test_account_id", None)) 78 | main(gads_client, id_to_load) 79 | --------------------------------------------------------------------------------