|
| 1 | +#!/usr/bin/python |
| 2 | +# |
| 3 | +# Copyright 2014 Google Inc. All Rights Reserved. |
| 4 | +# |
| 5 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | +# you may not use this file except in compliance with the License. |
| 7 | +# You may obtain a copy of the License at |
| 8 | +# |
| 9 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | +# |
| 11 | +# Unless required by applicable law or agreed to in writing, software |
| 12 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | +# See the License for the specific language governing permissions and |
| 15 | +# limitations under the License. |
| 16 | + |
| 17 | +"""Adds an ad customizer feed. |
| 18 | +
|
| 19 | +Associates the feed with customer and adds an ad that |
| 20 | +uses the feed to populate dynamic data. |
| 21 | +
|
| 22 | +Tags: CustomerFeedService.mutate, FeedItemService.mutate |
| 23 | +Tags: FeedMappingService.mutate, FeedService.mutate |
| 24 | +Tags: AdGroupAdService.mutate |
| 25 | +""" |
| 26 | + |
| 27 | +__author__ = ( '[email protected] (Mark Saniscalchi)', |
| 28 | + |
| 29 | + |
| 30 | +# Import appropriate classes from the client library. |
| 31 | +from googleads import adwords |
| 32 | + |
| 33 | +# See the Placeholder reference page for a list of all the placeholder types |
| 34 | +# and fields: |
| 35 | +# https://developers.google.com/adwords/api/docs/appendix/placeholders |
| 36 | +PLACEHOLDER_AD_CUSTOMIZER = '10' |
| 37 | +PLACEHOLDER_FIELD_INTEGER = '1' |
| 38 | +PLACEHOLDER_FIELD_FLOAT = '2' |
| 39 | +PLACEHOLDER_FIELD_PRICE = '3' |
| 40 | +PLACEHOLDER_FIELD_DATE = '4' |
| 41 | +PLACEHOLDER_FIELD_STRING = '5' |
| 42 | + |
| 43 | +ADGROUPS = [ |
| 44 | + 'INSERT_ADGROUP_ID_HERE', |
| 45 | + 'INSERT_ADGROUP_ID_HERE' |
| 46 | +] |
| 47 | + |
| 48 | +FEEDNAME = 'INSERT_FEED_NAME_HERE' |
| 49 | + |
| 50 | + |
| 51 | +def main(client, adgroups): |
| 52 | + # Initialize appropriate services. |
| 53 | + ad_group_ad_service = client.GetService('AdGroupAdService', version='v201406') |
| 54 | + customer_feed_service = client.GetService( |
| 55 | + 'CustomerFeedService', version='v201406') |
| 56 | + feed_item_service = client.GetService('FeedItemService', version='v201406') |
| 57 | + feed_mapping_service = client.GetService( |
| 58 | + 'FeedMappingService', version='v201406') |
| 59 | + feed_service = client.GetService('FeedService', version='v201406') |
| 60 | + |
| 61 | + # First, create a customizer feed. One feed per account can be used for all |
| 62 | + # ads. |
| 63 | + customizer_feed = { |
| 64 | + 'name': FEEDNAME, |
| 65 | + 'attributes': [ |
| 66 | + {'type': 'STRING', 'name': 'Name'}, |
| 67 | + {'type': 'STRING', 'name': 'Price'}, |
| 68 | + {'type': 'DATE_TIME', 'name': 'Date'} |
| 69 | + ] |
| 70 | + } |
| 71 | + |
| 72 | + feed_service_operation = { |
| 73 | + 'operator': 'ADD', |
| 74 | + 'operand': customizer_feed |
| 75 | + } |
| 76 | + |
| 77 | + response = feed_service.mutate([feed_service_operation]) |
| 78 | + |
| 79 | + if response and 'value' in response: |
| 80 | + feed = response['value'][0] |
| 81 | + feed_data = { |
| 82 | + 'feedId': feed['id'], |
| 83 | + 'nameId': feed['attributes'][0]['id'], |
| 84 | + 'priceId': feed['attributes'][1]['id'], |
| 85 | + 'dateId': feed['attributes'][2]['id'] |
| 86 | + } |
| 87 | + print ('Feed with name \'%s\' and ID %s was added with:' |
| 88 | + '\tName attribute ID %s and price attribute ID %s and date attribute' |
| 89 | + 'ID %s') % (feed['name'], feed['id'], feed_data['nameId'], |
| 90 | + feed_data['priceId'], feed_data['dateId']) |
| 91 | + else: |
| 92 | + raise Exception('No feeds were added') |
| 93 | + |
| 94 | + # Creating feed mapping to map the fields with customizer IDs. |
| 95 | + feed_mapping = { |
| 96 | + 'placeholderType': PLACEHOLDER_AD_CUSTOMIZER, |
| 97 | + 'feedId': feed_data['feedId'], |
| 98 | + 'attributeFieldMappings': [ |
| 99 | + { |
| 100 | + 'feedAttributeId': feed_data['nameId'], |
| 101 | + 'fieldId': PLACEHOLDER_FIELD_STRING |
| 102 | + }, |
| 103 | + { |
| 104 | + 'feedAttributeId': feed_data['priceId'], |
| 105 | + 'fieldId': PLACEHOLDER_FIELD_PRICE |
| 106 | + }, |
| 107 | + { |
| 108 | + 'feedAttributeId': feed_data['dateId'], |
| 109 | + 'fieldId': PLACEHOLDER_FIELD_DATE |
| 110 | + } |
| 111 | + ] |
| 112 | + } |
| 113 | + |
| 114 | + feed_mapping_operation = { |
| 115 | + 'operator': 'ADD', |
| 116 | + 'operand': feed_mapping |
| 117 | + } |
| 118 | + |
| 119 | + response = feed_mapping_service.mutate([feed_mapping_operation]) |
| 120 | + |
| 121 | + if response and 'value' in response: |
| 122 | + feed_mapping = response['value'][0] |
| 123 | + print ('Feed mapping with ID %s and placeholder type %s was saved for feed' |
| 124 | + ' with ID %s.') % (feed_mapping['feedMappingId'], |
| 125 | + feed_mapping['placeholderType'], |
| 126 | + feed_mapping['feedId']) |
| 127 | + else: |
| 128 | + raise Exception('No feed mappings were added.') |
| 129 | + |
| 130 | + # Now adding feed items -- the values we'd like to place. |
| 131 | + items_data = [ |
| 132 | + { |
| 133 | + 'name': 'Mars', |
| 134 | + 'price': '$1234.56', |
| 135 | + 'date': '20140601 000000', |
| 136 | + 'adGroupId': adgroups[0] |
| 137 | + }, |
| 138 | + { |
| 139 | + 'name': 'Venus', |
| 140 | + 'price': '$1450.00', |
| 141 | + 'date': '20140615 120000', |
| 142 | + 'adGroupId': adgroups[1] |
| 143 | + } |
| 144 | + ] |
| 145 | + |
| 146 | + feed_items = [{'feedId': feed_data['feedId'], |
| 147 | + 'adGroupTargeting': { |
| 148 | + 'TargetingAdGroupId': item['adGroupId'] |
| 149 | + }, |
| 150 | + 'attributeValues': [ |
| 151 | + { |
| 152 | + 'feedAttributeId': feed_data['nameId'], |
| 153 | + 'stringValue': item['name'] |
| 154 | + }, |
| 155 | + { |
| 156 | + 'feedAttributeId': feed_data['priceId'], |
| 157 | + 'stringValue': item['price'] |
| 158 | + }, |
| 159 | + { |
| 160 | + 'feedAttributeId': feed_data['dateId'], |
| 161 | + 'stringValue': item['date'] |
| 162 | + } |
| 163 | + ]} for item in items_data] |
| 164 | + |
| 165 | + feed_item_operations = [{ |
| 166 | + 'operator': 'ADD', |
| 167 | + 'operand': feed_item |
| 168 | + } for feed_item in feed_items] |
| 169 | + |
| 170 | + response = feed_item_service.mutate(feed_item_operations) |
| 171 | + |
| 172 | + if response and 'value' in response: |
| 173 | + for feed_item in response['value']: |
| 174 | + print 'Feed item with ID %s was added.' % feed_item['feedItemId'] |
| 175 | + else: |
| 176 | + raise Exception('No feed items were added.') |
| 177 | + |
| 178 | + # Finally, creating a customer (account-level) feed with a matching function |
| 179 | + # that determines when to use this feed. For this case we use the "IDENTITY" |
| 180 | + # matching function that is always 'true' just to associate this feed with |
| 181 | + # the customer. The targeting is done within the feed items using the |
| 182 | + # :campaign_targeting, :ad_group_targeting, or :keyword_targeting attributes. |
| 183 | + matching_function = { |
| 184 | + 'operator': 'IDENTITY', |
| 185 | + 'lhsOperand': [ |
| 186 | + { |
| 187 | + 'xsi_type': 'ConstantOperand', |
| 188 | + 'type': 'BOOLEAN', |
| 189 | + 'booleanValue': 'true' |
| 190 | + } |
| 191 | + ] |
| 192 | + } |
| 193 | + |
| 194 | + customer_feed = { |
| 195 | + 'feedId': feed_data['feedId'], |
| 196 | + 'matchingFunction': matching_function, |
| 197 | + 'placeholderTypes': [PLACEHOLDER_AD_CUSTOMIZER] |
| 198 | + } |
| 199 | + |
| 200 | + customer_feed_operation = { |
| 201 | + 'operator': 'ADD', |
| 202 | + 'operand': customer_feed |
| 203 | + } |
| 204 | + |
| 205 | + response = customer_feed_service.mutate([customer_feed_operation]) |
| 206 | + |
| 207 | + if response and 'value' in response: |
| 208 | + feed = response['value'][0] |
| 209 | + print 'Customer feed with ID %s was added.' % feed['feedId'] |
| 210 | + else: |
| 211 | + raise Exception('No customer feeds were added.') |
| 212 | + |
| 213 | + # All set! We can now create ads with customizations. |
| 214 | + text_ad = { |
| 215 | + 'xsi_type': 'TextAd', |
| 216 | + 'headline': 'Luxury Cruise to {=%s.Name}' % FEEDNAME, |
| 217 | + 'description1': 'Only {=%s.Price}' % FEEDNAME, |
| 218 | + 'description2': 'Offer ends in {=countdown(%s.Date)}!' % FEEDNAME, |
| 219 | + 'url': 'http://www.example.com', |
| 220 | + 'displayUrl': 'www.example.com' |
| 221 | + } |
| 222 | + |
| 223 | + # We add the same ad to both ad groups. When they serve, they will show |
| 224 | + # different values, since they match different feed items. |
| 225 | + operations = [{ |
| 226 | + 'operator': 'ADD', |
| 227 | + 'operand': { |
| 228 | + 'adGroupId': adgroup, |
| 229 | + 'ad': text_ad |
| 230 | + } |
| 231 | + } for adgroup in adgroups] |
| 232 | + |
| 233 | + print operations |
| 234 | + |
| 235 | + response = ad_group_ad_service.mutate(operations) |
| 236 | + |
| 237 | + print '===ad group ad service===' |
| 238 | + print response |
| 239 | + |
| 240 | + if response and 'value' in response: |
| 241 | + for ad in response['value']: |
| 242 | + print ('\tCreated an ad with ID \'%s\', type \'%s\', and status \'%s\'.' |
| 243 | + % (ad['ad']['id'], ad['ad']['Ad.Type'], ad['status'])) |
| 244 | + else: |
| 245 | + raise Exception('No ads were added.') |
| 246 | + |
| 247 | + |
| 248 | +if __name__ == '__main__': |
| 249 | + # Initialize client object. |
| 250 | + adwords_client = adwords.AdWordsClient.LoadFromStorage() |
| 251 | + main(adwords_client, ADGROUPS) |
0 commit comments