/
get_change_details.py
executable file
·216 lines (194 loc) · 9.29 KB
/
get_change_details.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#!/usr/bin/env python
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Gets specific details about the most recent changes in the given account.
Changes include the name of the field that changed, and both the old and new
values.
"""
import argparse
from datetime import datetime, timedelta
import sys
from proto.enums import ProtoEnumMeta
from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
from google.ads.googleads.util import get_nested_attr
_DEFAULT_PAGE_SIZE = 1000
# [START get_change_details]
def main(client, customer_id):
"""Gets specific details about the most recent changes in the given account.
Args:
client: The Google Ads client.
customer_id: The Google Ads customer ID.
"""
googleads_service = client.get_service("GoogleAdsService")
# Construct a query to find details for recent changes in your account.
# The LIMIT clause is required for the change_event resource.
# The maximum size is 10000, but a low limit was set here for demonstrative
# purposes. For more information see:
# https://developers.google.com/google-ads/api/docs/change-event#getting_changes
# The WHERE clause on change_date_time is also required. It must specify a
# window within the past 30 days.
tomorrow = (datetime.now() + timedelta(1)).strftime("%Y-%m-%d")
two_weeks_ago = (datetime.now() + timedelta(-14)).strftime("%Y-%m-%d")
query = f"""
SELECT
change_event.resource_name,
change_event.change_date_time,
change_event.change_resource_name,
change_event.user_email,
change_event.client_type,
change_event.change_resource_type,
change_event.old_resource,
change_event.new_resource,
change_event.resource_change_operation,
change_event.changed_fields
FROM change_event
WHERE change_event.change_date_time <= '{tomorrow}'
AND change_event.change_date_time >= '{two_weeks_ago}'
ORDER BY change_event.change_date_time DESC
LIMIT 5"""
search_request = client.get_type("SearchGoogleAdsRequest")
search_request.customer_id = customer_id
search_request.query = query
search_request.page_size = _DEFAULT_PAGE_SIZE
results = googleads_service.search(request=search_request)
for row in results:
event = row.change_event
resource_type = event.change_resource_type.name
if resource_type == "AD":
old_resource = event.old_resource.ad
new_resource = event.new_resource.ad
elif resource_type == "AD_GROUP":
old_resource = event.old_resource.ad_group
new_resource = event.new_resource.ad_group
elif resource_type == "AD_GROUP_AD":
old_resource = event.old_resource.ad_group_ad
new_resource = event.new_resource.ad_group_ad
elif resource_type == "AD_GROUP_ASSET":
old_resource = event.old_resource.ad_group_asset
new_resource = event.new_resource.ad_group_asset
elif resource_type == "AD_GROUP_CRITERION":
old_resource = event.old_resource.ad_group_criterion
new_resource = event.new_resource.ad_group_criterion
elif resource_type == "AD_GROUP_BID_MODIFIER":
old_resource = event.old_resource.ad_group_bid_modifier
new_resource = event.new_resource.ad_group_bid_modifier
elif resource_type == "AD_GROUP_FEED":
old_resource = event.old_resource.ad_group_feed
new_resource = event.new_resource.ad_group_feed
elif resource_type == "ASSET":
old_resource = event.old_resource.asset
new_resource = event.new_resource.asset
elif resource_type == "ASSET_SET":
old_resource = event.old_resource.asset_set
new_resource = event.new_resource.asset_set
elif resource_type == "ASSET_SET_ASSET":
old_resource = event.old_resource.asset_set_asset
new_resource = event.new_resource.asset_set_asset
elif resource_type == "CAMPAIGN":
old_resource = event.old_resource.campaign
new_resource = event.new_resource.campaign
elif resource_type == "CAMPAIGN_ASSET":
old_resource = event.old_resource.campaign_asset
new_resource = event.new_resource.campaign_asset
elif resource_type == "CAMPAIGN_ASSET_SET":
old_resource = event.old_resource.campaign_asset_set
new_resource = event.new_resource.campaign_asset_set
elif resource_type == "CAMPAIGN_BUDGET":
old_resource = event.old_resource.campaign_budget
new_resource = event.new_resource.campaign_budget
elif resource_type == "CAMPAIGN_CRITERION":
old_resource = event.old_resource.campaign_criterion
new_resource = event.new_resource.campaign_criterion
elif resource_type == "CAMPAIGN_FEED":
old_resource = event.old_resource.campaign_feed
new_resource = event.new_resource.campaign_feed
elif resource_type == "CUSTOMER_ASSET":
old_resource = event.old_resource.customer_asset
new_resource = event.new_resource.customer_asset
elif resource_type == "FEED":
old_resource = event.old_resource.feed
new_resource = event.new_resource.feed
elif resource_type == "FEED_ITEM":
old_resource = event.old_resource.feed_item
new_resource = event.new_resource.feed_item
else:
print(
"Unknown change_resource_type: '{event.change_resource_type}'"
)
# If the resource type is unrecognized then we continue to
# the next row.
continue
print(
f"On {event.change_date_time}, user {event.user_email} "
f"used interface {event.client_type.name} to perform a(n) "
f"{event.resource_change_operation.name} operation on a "
f"{event.change_resource_type.name} with resource name "
f"'{event.change_resource_name}'"
)
operation_type = event.resource_change_operation.name
if operation_type in ("UPDATE", "CREATE"):
for changed_field in event.changed_fields.paths:
# Change field name from "type" to "type_" so that it doesn't
# raise an exception when accessed on the protobuf object, see:
# https://developers.google.com/google-ads/api/docs/client-libs/python/library-version-10#field_names_that_are_reserved_words
if changed_field == "type":
changed_field = "type_"
new_value = get_nested_attr(new_resource, changed_field)
# If the field value is an Enum get the human readable name
# so that it is printed instead of the field ID integer.
if isinstance(type(new_value), ProtoEnumMeta):
new_value = new_value.name
if operation_type == "CREATE":
print(f"\t{changed_field} set to {new_value}")
else:
old_value = get_nested_attr(old_resource, changed_field)
# If the field value is an Enum get the human readable name
# so that it is printed instead of the field ID integer.
if isinstance(type(old_value), ProtoEnumMeta):
old_value = old_value.name
print(
f"\t{changed_field} changed from {old_value} to {new_value}"
)
# [END get_change_details]
if __name__ == "__main__":
# GoogleAdsClient will read the google-ads.yaml configuration file in the
# home directory if none is specified.
googleads_client = GoogleAdsClient.load_from_storage(version="v13")
parser = argparse.ArgumentParser(
description="This example gets specific details about the most recent "
"changes in the given account."
)
# The following argument(s) should be provided to run the example.
parser.add_argument(
"-c",
"--customer_id",
type=str,
required=True,
help="The Google Ads customer ID.",
)
args = parser.parse_args()
try:
main(googleads_client, args.customer_id)
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)