【问题标题】:Convert Google-Ads API GoogleAdsRow to json?将 Google-Ads API GoogleAdsRow 转换为 json?
【发布时间】:2019-04-01 14:53:43
【问题描述】:

我正在查询 google ads api,需要将结果保存为 json。 将 GoogleAdsRow 类型转换为 json 的最佳方法是什么?

google ads appi 的结果如下所示(广告系列和客户 ID 是假的):

campaign {
  resource_name: "customers/752830100/campaigns/22837002"
  id {
    value: 22837002
  }
  name {
    value: "test"
  }
}
metrics {
  clicks {
    value: 51
  }
  impressions {
    value: 33
  }
}

类型 = <class 'google.ads.googleads_v1.types.GoogleAdsRow'>

【问题讨论】:

    标签: python google-ads-api


    【解决方案1】:

    Google.protobuf 有一个名为 json_format 的方法可以做到这一点。 下面是一个帮助的代码示例:

    # Import the method 
    from google.protobuf import json_format
    import json
    
    # Query the Ads API, 
    ga_service = client.get_service('GoogleAdsService', version='YOUR_VERSION')
    query = ('YOUR_QUERY')
    
    # Response as an iterator made up of GoogleAdsRow  
    response = ga_service.search(customer_id, query)
    
    # Converting each of the GoogleAdsRow to json
    for row in response : 
        json_str = json_format.MessageToJson(row)
        d = json.loads(json_str)
    

    【讨论】:

    • 太棒了,感谢分享!如果有人因为想将 google ads api 结果转换为数据框而最终来到这里,您只需在上面添加以下行:df = pd.json_normalize(data=d['results'])
    • 这对我有用,但在我的 row 对象中添加了 ._pb,例如MessageToJson(row._pb)。否则我会收到“DESCRIPTOR”错误消息。请参阅此答案:stackoverflow.com/a/68216092,第 3 节。
    【解决方案2】:

    现在我也在寻找同样的问题。我发现的一种解决方法是在 json.dumps 中使用 CustomEncoder。这是一个示例:

    class CustomEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (google.protobuf.wrappers_pb2.StringValue,
                            google.protobuf.wrappers_pb2.Int64Value, 
                            google.protobuf.wrappers_pb2.DoubleValue)):
            return obj.value
    
        elif isinstance(obj, google.protobuf.pyext._message.RepeatedCompositeContainer):
            data = []
            try:
                while True:
                    item = obj.pop()
                    data.append(self.default(item))
            except IndexError:
                return data
    
        elif isinstance(obj, google.ads.google_ads.v1.proto.common.custom_parameter_pb2.CustomParameter):
            return { 
                    self.default(obj.key): self.default(obj.value) 
                    }
    return json.JSONEncoder.default(self, obj)
    

    json.dumps(data, cls=CustomEncoder)中使用上述编码器

    这是迄今为止我提供的唯一解决方案。如果我找到更好的解决方案会更新它。

    编辑: 找到解决方案。这是 New Encoder 类。

    class GoogleProtoEncoder(json.JSONEncoder):
    """
    Custom JSON Encoder for GoogleAdsRow. 
    
    Usage: json.dumps(data, cls=GoogleProtoEncoder)
    """
    def default(self, obj):
        """
        Overriden method. When json.dumps() is called, it actually calls this method if 
        this class is specified as the encoder in json.dumps().
        """
        if isinstance(obj, google.protobuf.message.Message) and hasattr(obj, 'value'):
            # This covers native data types such as string, int, float etc
            return obj.value
    
        elif isinstance(obj, google.protobuf.pyext._message.RepeatedCompositeContainer):
            # This is basically for python list and tuples
            data = []
            try:
                while True:
                    item = obj.pop()
                    data.append(self.default(item))
            except IndexError:
                return data
    
        elif isinstance(obj, google.ads.google_ads.v1.proto.common.custom_parameter_pb2.CustomParameter):
            # Equivalent to python dictionary
            return { 
                    self.default(obj.key): self.default(obj.value) 
                    }
    
        elif isinstance(obj, google.protobuf.message.Message):
            # All the other wrapper objects which can have different fields.
            return {key[0].name: getattr(obj, key[0].name) for key in obj.ListFields()}
    
        return json.JSONEncoder.default(self, obj)
    

    谢谢。

    已编辑:更新的解决方案。在 V7 中工作

    import proto
    
    response = ga_service.search_stream(search_request)
    for batch in response:
        for row in batch.results:
            logging.debug(proto.Message.to_dict(row))
    

    【讨论】:

    • 这在使用以前版本的 API 时效果很好。你知道V3有什么变化吗?需要更新什么?
    • 嗨,我遇到了一个问题,使用代码。尽管它在我遇到问题的绝大多数时间都有效。我正在运行 v5,因为它们现在允许检索发现活动。我在我的一次提取中遇到了这个问题TypeError: Object of type RepeatedScalarContainer is not JSON serializable
    • @DaveDavis @spak 道歉.. 我还没有查看较新的版本.. 我建议您检查RepeatedScalarContainer 的结构并添加另一个elif 语句以进行相应的转换。
    【解决方案3】:

    如果不用SDK,另一种获取json的方法是直接查询发送post请求的API,返回json响应:

    r = requests.post('https://googleads.googleapis.com/v3/customers/YOUR_CUSTOMER_ID/googleAds:searchStream', 
                     headers={'Authorization': f'Bearer {access_token}',
                             'developer-token' : developer_token,
                             'login-customer-id' : 'YOUR_CUSTOMER_ID',
                             'Content-Type': 'application/json'},
                    params={"query" : query})
    

    【讨论】:

      【解决方案4】:

      第 1 步:导入此库

      from google.ads.googleads.errors import GoogleAdsException
      

      第 2 步:发送请求

      keyword_ideas = keyword_plan_idea_service.generate_keyword_ideas(
          request=request
      )
      

      第 3 步:将响应转换为 json

      keyword_ideas_json = MessageToDict(keyword_ideas)
      

      第四步:用json做任何你想做的事

      print(keyword_ideas_json)
      

      注意:这可能是 attribute error: "DESCRIPTOR" 错误,因此请查看以下答案:here

      【讨论】:

        【解决方案5】:

        您现在可以使用此处概述的自定义 protobuf 辅助方法: https://developers.google.com/google-ads/api/docs/client-libs/python/library-version-10#wrapped_versus_native_protobuf_messages

        campaign = client.get_type("Campaign")
        json = type(campaign).to_json(campaign)
        campaign = type(campaign).from_json(json)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-12-15
          • 2018-07-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-27
          相关资源
          最近更新 更多