将 Google-Ads API GoogleAdsRow 转换为 json?

use*_*823 4 python google-ads-api

我正在查询 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
  }
}
Run Code Online (Sandbox Code Playgroud)

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

小智 5

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)
Run Code Online (Sandbox Code Playgroud)

  • 这对我有用,但在我的“row”对象中添加了“._pb”,例如“MessageToJson(row._pb)”。否则我会收到“DESCRIPTOR”错误消息。请参阅此答案:/sf/answers/4775126471/,第 3 节。 (4认同)
  • 将 `MessageToJson` 更改为 `MessageToDict` ,您可以跳过 json 的加载 (3认同)
  • 太棒了,感谢分享!如果有人因为想要将 google ads api 结果转换为数据帧而最终来到这里,您只需将以下行添加到上面: df = pd.json_normalize(data=d['results']) (2认同)

Rah*_*mar 3

现在我也在寻找同样的问题。我发现的一种解决方法是在 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)
Run Code Online (Sandbox Code Playgroud)

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

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

编辑:找到解决方案。这是新的编码器类。

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)
Run Code Online (Sandbox Code Playgroud)

谢谢。

编辑:更新的解决方案。适用于 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))
Run Code Online (Sandbox Code Playgroud)