如何通过Python基于新版Google Ads API自动化获取Geo Performance Report等性能报告?
适配新版Google Ads API获取性能报表的解决方案
我明白你在把旧版Google Ads API(v201809)的报表逻辑迁移到新版时碰了壁——新版API彻底抛弃了旧版的ReportDownloader和预定义报表类型,改用**GAQL(Google Ads Query Language)**来实现数据查询,灵活性更强但写法和旧版差异很大。下面给你一套完整的可运行方案,包含关键词报表、地域报表等常见性能报表的获取流程。
核心思路说明
新版Google Ads API没有了KEYWORDS_PERFORMANCE_REPORT这种预定义报表类型,你需要用GAQL编写类似SQL的查询语句,指定要获取的字段、过滤条件(比如日期范围),然后通过GoogleAdsService的search_stream或search方法拉取数据,最后转换成DataFrame格式。
完整实现代码
import io import sys import pandas as pd from datetime import datetime, timedelta from google.ads.googleads.client import GoogleAdsClient from google.ads.googleads.errors import GoogleAdsException def fetch_googleads_report(client, customer_id, gaql_query): """ 通过新版Google Ads API获取报表数据并转换为DataFrame Args: client: GoogleAdsClient实例 customer_id: 客户ID(不带连字符) gaql_query: 完整的GAQL查询语句 Returns: pandas.DataFrame: 报表数据 """ ga_service = client.get_service("GoogleAdsService") results = [] try: # 使用search_stream处理大数据量,避免内存溢出 response = ga_service.search_stream(customer_id=customer_id, query=gaql_query) for batch in response: for row in batch.results: # 将Google Ads API返回的行数据转换为字典 row_dict = {} for field in row._pb.DESCRIPTOR.fields: value = getattr(row, field.name) # 处理不同类型的字段值(比如枚举、消息类型) if field.type == field.TYPE_ENUM: enum_value = client.get_type(field.message_type.name).Name(value) row_dict[field.name] = enum_value elif field.type == field.TYPE_MESSAGE: # 处理嵌套字段,比如metrics.clicks for sub_field in value._pb.DESCRIPTOR.fields: sub_value = getattr(value, sub_field.name) row_dict[f"{field.name}_{sub_field.name}"] = sub_value else: row_dict[field.name] = value results.append(row_dict) # 转换为DataFrame df = pd.DataFrame(results) return df 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) def main(client, customer_id): # 定义日期范围 today = datetime.now().date() yesterday = today - timedelta(days=1) start_date = "2019-01-01" end_date = yesterday.strftime("%Y-%m-%d") # -------------------------- # 1. 获取关键词性能报表(对应旧版KEYWORDS_PERFORMANCE_REPORT) # -------------------------- keyword_gaql = f""" SELECT segments.date, customer.descriptive_name, ad_group.id, ad_group.name, ad_group.status, campaign.id, campaign.name, campaign.status, ad_group_criterion.cpc_bid_micros, ad_group_criterion.keyword.text, ad_group_criterion.keyword.match_type, ad_group_criterion.status, metrics.clicks, metrics.conversions, metrics.cost_micros, metrics.conversion_value, metrics.impressions, metrics.view_through_conversions, ad_group_criterion.quality_info.quality_score, ad_group_criterion.quality_info.search_impression_share, ad_group_criterion.quality_info.first_page_cpc_micros, ad_group_criterion.quality_info.first_position_cpc_micros, ad_group_criterion.quality_info.top_of_page_cpc_micros FROM keyword_view WHERE segments.date BETWEEN '{start_date}' AND '{end_date}' AND ad_group_criterion.status != 'REMOVED' """ keyword_df = fetch_googleads_report(client, customer_id, keyword_gaql) # 处理微单位转换(比如cost_micros转为美元,除以1e6) keyword_df["ad_group_criterion_cpc_bid_micros"] = keyword_df["ad_group_criterion_cpc_bid_micros"] / 1e6 keyword_df["metrics_cost_micros"] = keyword_df["metrics_cost_micros"] / 1e6 keyword_df["ad_group_criterion_quality_info_first_page_cpc_micros"] = keyword_df["ad_group_criterion_quality_info_first_page_cpc_micros"] / 1e6 print("关键词报表前5行:") print(keyword_df.head()) keyword_df.to_csv("keywords_performance_report.csv", index=False) # -------------------------- # 2. 获取地域性能报表(对应旧版GEO_PERFORMANCE_REPORT) # -------------------------- geo_gaql = f""" SELECT segments.date, customer.descriptive_name, campaign.id, campaign.name, campaign.status, geo_target_constant.country_code, geo_target_constant.name, metrics.clicks, metrics.conversions, metrics.cost_micros, metrics.impressions, metrics.conversion_value FROM geo_view WHERE segments.date BETWEEN '{start_date}' AND '{end_date}' """ geo_df = fetch_googleads_report(client, customer_id, geo_gaql) geo_df["metrics_cost_micros"] = geo_df["metrics_cost_micros"] / 1e6 print("\n地域报表前5行:") print(geo_df.head()) geo_df.to_csv("geo_performance_report.csv", index=False) if __name__ == "__main__": # 加载配置文件(google-ads.yaml需要放在指定路径,或者传入path参数) try: googleads_client = GoogleAdsClient.load_from_storage(path="mypath/google-ads.yaml") except FileNotFoundError: print("请确保google-ads.yaml配置文件路径正确!") sys.exit(1) # 替换为你的客户ID(不带连字符) customer_id = "#######" main(googleads_client, customer_id)
关键细节说明
- GAQL查询编写:
- 你可以通过官方的查询构建工具可视化生成GAQL语句,避免字段拼写错误。
- 不同报表对应不同的
FROM子句:关键词报表用keyword_view,地域报表用geo_view,广告报表用ad_view,活动报表用campaign_view。
- 字段单位转换:新版API中涉及金额、出价的字段都是以微单位存储的(比如1美元=1,000,000微美元),所以需要除以1e6转换为实际金额。
- 数据拉取方式:推荐用
search_stream而不是search,因为当数据量很大时,search_stream会分批返回结果,避免内存溢出。 - 错误处理:保留了GoogleAdsException的捕获逻辑,方便排查API调用失败的原因。
迁移注意事项
- 旧版的
ExternalCustomerId对应新版的customer.id,但通常你已经传入了customer_id,所以不需要额外查询。 - 旧版的
Labels字段在新版中需要通过ad_group_criterion.labels或campaign.labels关联查询,如果你需要标签数据,可以在GAQL中添加SELECT ... ad_group_criterion.labels ...并处理嵌套字段。
内容的提问来源于stack exchange,提问作者LIONEL JOSEPH
相关产品推荐
相关产品推荐

