Google Ads API Python 403请求的身份验证作用域不足

2024-06-01 21:21:05 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试从Python中访问Google Ads campaing报告,如下this tutorial

我已请求具有基本访问权限的开发者令牌。我认为它必须执行脚本。当我进入谷歌广告中的“API中心”时,我可以看到我的令牌处于活动状态

我在google cloud中创建了一个项目和一个Oauth令牌

在谷歌云中:

  • 创建了一个新项目
  • 激活了谷歌广告API
  • 当我开始管理时->;我看到Oauth令牌与该API兼容
  • 我已成功创建刷新令牌

我使用此脚本作为概念证明:

import os
import json

import sys
from google.ads.google_ads.errors import GoogleAdsException

# Put an account id to download stats from. Note: not MCC, no dash lines
CUSTOMER_ID = "xxxxxxxxxx"


def get_account_id(account_id, check_only=False):
    """
    Converts int to str, checks if str has dashes. Returns 10 chars str or raises error
    :check_only - if True, returns None instead of Error

    """

    if isinstance(account_id, int) and len(str(account_id)) == 10:
        return str(account_id)
    if isinstance(account_id, str) and len(account_id.replace("-", "")) == 10:
        return account_id.replace("-", "")
    if check_only:
        return None
    raise ValueError(f"Couldn't recognize account id from {account_id}")


def micros_to_currency(micros):
    return micros / 1000000.0




def main(client, customer_id):
    
    ga_service = client.get_service("GoogleAdsService")#     , version="v5")

    query = """
        SELECT
          campaign.id,
          campaign.name,
          ad_group.id,
          ad_group.name,
          ad_group_criterion.criterion_id,
          ad_group_criterion.keyword.text,
          ad_group_criterion.keyword.match_type,
          metrics.impressions,
          metrics.clicks,
          metrics.cost_micros
        FROM keyword_view
        WHERE
          segments.date DURING LAST_7_DAYS
          AND campaign.advertising_channel_type = 'SEARCH'
          AND ad_group.status = 'ENABLED'
          AND ad_group_criterion.status IN ('ENABLED', 'PAUSED')
        ORDER BY metrics.impressions DESC
        LIMIT 50"""

    # Issues a search request using streaming.
    response = ga_service.search_stream(customer_id, query) #THIS LINE GENERATES THE ERROR
    keyword_match_type_enum = client.get_type(
        "KeywordMatchTypeEnum"
    ).KeywordMatchType
    try:
        for batch in response:
            for row in batch.results:
                campaign = row.campaign
                ad_group = row.ad_group
                criterion = row.ad_group_criterion
                metrics = row.metrics
                keyword_match_type = keyword_match_type_enum.Name(
                    criterion.keyword.match_type
                )
                print(
                    f'Keyword text "{criterion.keyword.text}" with '
                    f'match type "{keyword_match_type}" '
                    f"and ID {criterion.criterion_id} in "
                    f'ad group "{ad_group.name}" '
                    f'with ID "{ad_group.id}" '
                    f'in campaign "{campaign.name}" '
                    f"with ID {campaign.id} "
                    f"had {metrics.impressions} impression(s), "
                    f"{metrics.clicks} click(s), and "
                    f"{metrics.cost_micros} cost (in micros) during "
                    "the last 7 days."
                )
    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)


if __name__ == "__main__":


    # credentials dictonary
    creds = {"google_ads": "googleads.yaml"}


    if not os.path.isfile(creds["google_ads"]):
        raise FileExistsError("File googleads.yaml doesn't exists. ")

    resources = {"config": "config.json"}


    # This logging allows to see additional information on debugging
    import logging
    logging.basicConfig(level=logging.INFO, format='[%(asctime)s - %(levelname)s] %(message).5000s')
    logging.getLogger('google.ads.google_ads.client').setLevel(logging.DEBUG)


    # Initialize the google_ads client
    from google.ads.google_ads.client import GoogleAdsClient
    gads_client = GoogleAdsClient.load_from_storage(creds["google_ads"])

    id_to_load = get_account_id(CUSTOMER_ID) 
    main(gads_client, id_to_load)
  • 我已将CUSTOMER_ID更改为显示在左上角的帐号
  • 我已经创建了一个googleads.yaml并加载了上述信息

当我执行脚本时,会出现以下错误:

Traceback (most recent call last):
 File "download_keywords_from_account.py", line 138, in <module>
   main(gads_client, id_to_load)
 File "download_keywords_from_account.py", line 70, in main
   response = ga_service.search_stream(customer_id, query)
 File "google/ads/google_ads/v6/services/google_ads_service_client.py", line 366, in search_stream
   return self._inner_api_calls['search_stream'](request, retry=retry, timeout=timeout, metadata=metadata)
 File google/api_core/gapic_v1/method.py", line 145, in __call__
   return wrapped_func(*args, **kwargs)
 File "google/api_core/retry.py", line 281, in retry_wrapped_func
   return retry_target(
 File "google/api_core/retry.py", line 184, in retry_target
   return target()
 File "google/api_core/timeout.py", line 214, in func_with_timeout
   return func(*args, **kwargs)
 File "google/api_core/grpc_helpers.py", line 152, in error_remapped_callable
   six.raise_from(exceptions.from_grpc_error(exc), exc)
 File "<string>", line 3, in raise_from
google.api_core.exceptions.PermissionDenied: 403 Request had insufficient authentication scopes

googleads.yaml文件如下所示:

  #############################################################################
  # Required Fields                                                           #
  #############################################################################
  developer_token: {developer token as seen in google ads -> tools -> api center}
  #############################################################################
  # Optional Fields                                                           #
  #############################################################################
  login_customer_id: {Id from the top left corner in google ads, only numbers}
  # user_agent: INSERT_USER_AGENT_HERE
  # partial_failure: True
  validate_only: False
  #############################################################################
  # 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: {Oauth client id taken from gcloud -> api -> credentials} ends with apps.googleusercontent.com
  client_secret: {got it while generating the token}
  refresh_token:  1//0hr.... made with generate_refresh_token.py 
  # The following values configure the client for the service account flow.
  path_to_private_key_file: ads.json
  # delegated_account: INSERT_DOMAIN_WIDE_DELEGATION_ACCOUNT
  #############################################################################
  # ReportDownloader Headers                                                  #
  # Below you may specify boolean values for optional headers that will be    #
  # applied to all requests made by the ReportDownloader utility by default.  #
  #############################################################################
  # report_downloader_headers:
    # skip_report_header: False
    # skip_column_header: False
    # skip_report_summary: False
    # use_raw_enum_values: False

注意事项:

文件ads.json包含从gcloud的凭据页面下载的私钥

我已经看过一些关于这个问题的帖子,但是没有一篇是Python+GoogleADs,我在那里也找不到解决方案

我还尝试过其他Python+GoogleAds示例,它们也出现了相同的错误。这让我 我想我一定是在gcloud/google广告中配置错误了。但我不明白是什么

请帮我提问,我真的卡住了

非常感谢


Tags: thetoinfromclientidreturngoogle