google-adwords-api 0.21.0 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ChangeLog +5 -0
- data/examples/v201603/shopping_campaigns/add_product_scope.rb +3 -2
- data/examples/v201605/shopping_campaigns/add_product_scope.rb +3 -2
- data/examples/v201607/shopping_campaigns/add_product_scope.rb +3 -2
- data/examples/v201609/account_management/create_account.rb +88 -0
- data/examples/v201609/account_management/get_account_changes.rb +135 -0
- data/examples/v201609/account_management/get_account_hierarchy.rb +132 -0
- data/examples/v201609/advanced_operations/add_ad_customizers.rb +183 -0
- data/examples/v201609/advanced_operations/add_ad_group_bid_modifier.rb +101 -0
- data/examples/v201609/advanced_operations/add_click_to_download_ad.rb +148 -0
- data/examples/v201609/advanced_operations/add_expanded_text_ad_with_upgraded_urls.rb +132 -0
- data/examples/v201609/advanced_operations/add_html5_ad.rb +137 -0
- data/examples/v201609/advanced_operations/add_responsive_display_ad.rb +130 -0
- data/examples/v201609/advanced_operations/add_universal_app_campaign.rb +215 -0
- data/examples/v201609/advanced_operations/create_and_attach_shared_keyword_set.rb +141 -0
- data/examples/v201609/advanced_operations/find_and_remove_criteria_from_shared_set.rb +174 -0
- data/examples/v201609/advanced_operations/get_ad_group_bid_modifiers.rb +102 -0
- data/examples/v201609/advanced_operations/use_portfolio_bidding_strategy.rb +146 -0
- data/examples/v201609/basic_operations/add_ad_groups.rb +142 -0
- data/examples/v201609/basic_operations/add_campaigns.rb +138 -0
- data/examples/v201609/basic_operations/add_expanded_text_ads.rb +108 -0
- data/examples/v201609/basic_operations/add_keywords.rb +114 -0
- data/examples/v201609/basic_operations/get_ad_groups.rb +102 -0
- data/examples/v201609/basic_operations/get_campaigns.rb +97 -0
- data/examples/v201609/basic_operations/get_campaigns_with_awql.rb +89 -0
- data/examples/v201609/basic_operations/get_expanded_text_ads.rb +122 -0
- data/examples/v201609/basic_operations/get_keywords.rb +109 -0
- data/examples/v201609/basic_operations/get_text_ads.rb +109 -0
- data/examples/v201609/basic_operations/pause_ad.rb +87 -0
- data/examples/v201609/basic_operations/remove_ad.rb +89 -0
- data/examples/v201609/basic_operations/remove_ad_group.rb +85 -0
- data/examples/v201609/basic_operations/remove_campaign.rb +87 -0
- data/examples/v201609/basic_operations/remove_keyword.rb +94 -0
- data/examples/v201609/basic_operations/update_ad_group.rb +85 -0
- data/examples/v201609/basic_operations/update_campaign.rb +86 -0
- data/examples/v201609/basic_operations/update_keyword.rb +106 -0
- data/examples/v201609/campaign_management/add_campaign_labels.rb +82 -0
- data/examples/v201609/campaign_management/add_complete_campaigns_using_batch_job.rb +354 -0
- data/examples/v201609/campaign_management/add_draft.rb +113 -0
- data/examples/v201609/campaign_management/add_keywords_using_incremental_batch_job.rb +210 -0
- data/examples/v201609/campaign_management/add_trial.rb +141 -0
- data/examples/v201609/campaign_management/get_all_disapproved_ads.rb +97 -0
- data/examples/v201609/campaign_management/get_all_disapproved_ads_with_awql.rb +89 -0
- data/examples/v201609/campaign_management/get_campaigns_by_label.rb +108 -0
- data/examples/v201609/campaign_management/graduate_trial.rb +106 -0
- data/examples/v201609/campaign_management/set_ad_parameters.rb +118 -0
- data/examples/v201609/campaign_management/set_criterion_bid_modifier.rb +104 -0
- data/examples/v201609/campaign_management/validate_text_ad.rb +109 -0
- data/examples/v201609/error_handling/handle_partial_failures.rb +130 -0
- data/examples/v201609/error_handling/handle_policy_violation_error.rb +141 -0
- data/examples/v201609/extensions/add_google_my_business_location_extensions.rb +193 -0
- data/examples/v201609/extensions/add_prices.rb +162 -0
- data/examples/v201609/extensions/add_site_links.rb +199 -0
- data/examples/v201609/extensions/add_site_links_using_feeds.rb +286 -0
- data/examples/v201609/migration/migrate_to_extension_settings.rb +386 -0
- data/examples/v201609/misc/get_all_images_and_videos.rb +104 -0
- data/examples/v201609/misc/setup_oauth2.rb +84 -0
- data/examples/v201609/misc/upload_image.rb +93 -0
- data/examples/v201609/misc/upload_media_bundle.rb +90 -0
- data/examples/v201609/misc/use_oauth2_jwt.rb +93 -0
- data/examples/v201609/misc/use_runtime_config.rb +92 -0
- data/examples/v201609/optimization/estimate_keyword_traffic.rb +191 -0
- data/examples/v201609/optimization/get_campaign_criterion_bid_modifier_simulations.rb +128 -0
- data/examples/v201609/optimization/get_keyword_bid_simulations.rb +95 -0
- data/examples/v201609/optimization/get_keyword_ideas.rb +136 -0
- data/examples/v201609/remarketing/add_audience.rb +118 -0
- data/examples/v201609/remarketing/add_conversion_tracker.rb +97 -0
- data/examples/v201609/remarketing/add_crm_based_user_list.rb +116 -0
- data/examples/v201609/remarketing/add_rule_based_user_lists.rb +167 -0
- data/examples/v201609/remarketing/upload_offline_call_conversions.rb +111 -0
- data/examples/v201609/remarketing/upload_offline_conversions.rb +98 -0
- data/examples/v201609/reporting/download_criteria_report.rb +92 -0
- data/examples/v201609/reporting/download_criteria_report_with_awql.rb +93 -0
- data/examples/v201609/reporting/get_report_fields.rb +75 -0
- data/examples/v201609/reporting/parallel_report_download.rb +164 -0
- data/examples/v201609/reporting/stream_criteria_report_results.rb +97 -0
- data/examples/v201609/shopping_campaigns/add_product_partition_tree.rb +267 -0
- data/examples/v201609/shopping_campaigns/add_product_scope.rb +130 -0
- data/examples/v201609/shopping_campaigns/add_shopping_campaign.rb +129 -0
- data/examples/v201609/shopping_campaigns/get_product_category_taxonomy.rb +115 -0
- data/examples/v201609/targeting/add_campaign_targeting_criteria.rb +166 -0
- data/examples/v201609/targeting/add_demographic_targeting_criteria.rb +112 -0
- data/examples/v201609/targeting/get_campaign_targeting_criteria.rb +106 -0
- data/examples/v201609/targeting/get_targetable_languages_and_carriers.rb +89 -0
- data/examples/v201609/targeting/lookup_location.rb +108 -0
- data/lib/adwords_api/api_config.rb +96 -4
- data/lib/adwords_api/batch_job_utils.rb +6 -0
- data/lib/adwords_api/report_utils.rb +9 -4
- data/lib/adwords_api/v201609/account_label_service.rb +46 -0
- data/lib/adwords_api/v201609/account_label_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/ad_customizer_feed_service.rb +46 -0
- data/lib/adwords_api/v201609/ad_customizer_feed_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/ad_group_ad_service.rb +70 -0
- data/lib/adwords_api/v201609/ad_group_ad_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/ad_group_bid_modifier_service.rb +54 -0
- data/lib/adwords_api/v201609/ad_group_bid_modifier_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/ad_group_criterion_service.rb +62 -0
- data/lib/adwords_api/v201609/ad_group_criterion_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/ad_group_extension_setting_service.rb +54 -0
- data/lib/adwords_api/v201609/ad_group_extension_setting_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/ad_group_feed_service.rb +54 -0
- data/lib/adwords_api/v201609/ad_group_feed_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/ad_group_service.rb +62 -0
- data/lib/adwords_api/v201609/ad_group_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/ad_param_service.rb +46 -0
- data/lib/adwords_api/v201609/ad_param_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/adwords_user_list_service.rb +62 -0
- data/lib/adwords_api/v201609/adwords_user_list_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/batch_job_service.rb +54 -0
- data/lib/adwords_api/v201609/batch_job_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/bidding_strategy_service.rb +54 -0
- data/lib/adwords_api/v201609/bidding_strategy_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/budget_order_service.rb +54 -0
- data/lib/adwords_api/v201609/budget_order_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/budget_service.rb +54 -0
- data/lib/adwords_api/v201609/budget_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/campaign_criterion_service.rb +54 -0
- data/lib/adwords_api/v201609/campaign_criterion_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/campaign_extension_setting_service.rb +54 -0
- data/lib/adwords_api/v201609/campaign_extension_setting_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/campaign_feed_service.rb +54 -0
- data/lib/adwords_api/v201609/campaign_feed_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/campaign_service.rb +62 -0
- data/lib/adwords_api/v201609/campaign_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/campaign_shared_set_service.rb +54 -0
- data/lib/adwords_api/v201609/campaign_shared_set_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/constant_data_service.rb +110 -0
- data/lib/adwords_api/v201609/constant_data_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/conversion_tracker_service.rb +54 -0
- data/lib/adwords_api/v201609/conversion_tracker_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/customer_extension_setting_service.rb +54 -0
- data/lib/adwords_api/v201609/customer_extension_setting_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/customer_feed_service.rb +54 -0
- data/lib/adwords_api/v201609/customer_feed_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/customer_service.rb +62 -0
- data/lib/adwords_api/v201609/customer_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/customer_sync_service.rb +38 -0
- data/lib/adwords_api/v201609/customer_sync_service_registry.rb +47 -0
- data/lib/adwords_api/v201609/data_service.rb +94 -0
- data/lib/adwords_api/v201609/data_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/draft_async_error_service.rb +46 -0
- data/lib/adwords_api/v201609/draft_async_error_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/draft_service.rb +54 -0
- data/lib/adwords_api/v201609/draft_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/feed_item_service.rb +54 -0
- data/lib/adwords_api/v201609/feed_item_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/feed_mapping_service.rb +54 -0
- data/lib/adwords_api/v201609/feed_mapping_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/feed_service.rb +54 -0
- data/lib/adwords_api/v201609/feed_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/label_service.rb +54 -0
- data/lib/adwords_api/v201609/label_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/location_criterion_service.rb +46 -0
- data/lib/adwords_api/v201609/location_criterion_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/managed_customer_service.rb +78 -0
- data/lib/adwords_api/v201609/managed_customer_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/media_service.rb +54 -0
- data/lib/adwords_api/v201609/media_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/offline_call_conversion_feed_service.rb +38 -0
- data/lib/adwords_api/v201609/offline_call_conversion_feed_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/offline_conversion_feed_service.rb +38 -0
- data/lib/adwords_api/v201609/offline_conversion_feed_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/report_definition_service.rb +38 -0
- data/lib/adwords_api/v201609/report_definition_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/shared_criterion_service.rb +54 -0
- data/lib/adwords_api/v201609/shared_criterion_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/shared_set_service.rb +54 -0
- data/lib/adwords_api/v201609/shared_set_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/targeting_idea_service.rb +38 -0
- data/lib/adwords_api/v201609/targeting_idea_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/traffic_estimator_service.rb +38 -0
- data/lib/adwords_api/v201609/traffic_estimator_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/trial_async_error_service.rb +46 -0
- data/lib/adwords_api/v201609/trial_async_error_service_registry.rb +46 -0
- data/lib/adwords_api/v201609/trial_service.rb +54 -0
- data/lib/adwords_api/v201609/trial_service_registry.rb +46 -0
- data/lib/adwords_api/version.rb +1 -1
- data/test/adwords_api/test_adwords_api.rb +1 -1
- data/test/adwords_api/test_api_config.rb +8 -8
- data/test/adwords_api/test_batch_job_utils.rb +2 -2
- data/test/adwords_api/test_choices.rb +2 -2
- data/test/adwords_api/test_report_stream.rb +1 -1
- data/test/adwords_api/test_report_utils.rb +1 -1
- data/test/templates/v201609/basic_operations_get_campaigns.def +116 -0
- data/test/templates/v201609/basic_operations_update_keyword.def +125 -0
- data/test/templates/v201609/misc_use_oauth2_jwt.def +131 -0
- metadata +174 -2
@@ -0,0 +1,354 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Encoding: utf-8
|
3
|
+
#
|
4
|
+
# Copyright:: Copyright 2015, Google Inc. All Rights Reserved.
|
5
|
+
#
|
6
|
+
# License:: Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
15
|
+
# implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
# This code sample illustrates how to use BatchJobService to create a complete
|
20
|
+
# campaign, including ad groups and keywords.
|
21
|
+
|
22
|
+
require 'adwords_api'
|
23
|
+
|
24
|
+
def add_complete_campaigns_using_batch_job()
|
25
|
+
# AdwordsApi::Api will read a config file from ENV['HOME']/adwords_api.yml
|
26
|
+
# when called without parameters.
|
27
|
+
adwords = AdwordsApi::Api.new
|
28
|
+
|
29
|
+
# To enable logging of SOAP requests, set the log_level value to 'DEBUG' in
|
30
|
+
# the configuration file or provide your own logger:
|
31
|
+
# adwords.logger = Logger.new('adwords_xml.log')
|
32
|
+
|
33
|
+
batch_job_srv = adwords.service(:BatchJobService, API_VERSION)
|
34
|
+
batch_job_utils = adwords.batch_job_utils(API_VERSION)
|
35
|
+
|
36
|
+
# Create a BatchJob.
|
37
|
+
add_op = {
|
38
|
+
:operator => 'ADD',
|
39
|
+
:operand => {}
|
40
|
+
}
|
41
|
+
|
42
|
+
response = batch_job_srv.mutate([add_op])
|
43
|
+
batch_job = response[:value].first
|
44
|
+
|
45
|
+
# Get the upload URL from the new job.
|
46
|
+
upload_url = batch_job[:upload_url][:url]
|
47
|
+
puts "Created BatchJob with ID %d, status '%s', and upload URL %s." %
|
48
|
+
[batch_job[:id], batch_job[:status], upload_url]
|
49
|
+
|
50
|
+
# Create a temporary ID generator that will produce a sequence of descending
|
51
|
+
# negative numbers.
|
52
|
+
temp_id_generator = TempIdGenerator.new()
|
53
|
+
|
54
|
+
# Create an array of hashed operations generated from the batch_job_utils.
|
55
|
+
operations = []
|
56
|
+
|
57
|
+
# Create an operation to create a new budget.
|
58
|
+
budget_operation = build_budget_operation(temp_id_generator)
|
59
|
+
operations << budget_operation
|
60
|
+
|
61
|
+
# Create operations to create new campaigns.
|
62
|
+
campaign_operations = build_campaign_operations(
|
63
|
+
temp_id_generator, budget_operation)
|
64
|
+
operations += campaign_operations
|
65
|
+
|
66
|
+
# Create operations to create new negative keyword criteria for each
|
67
|
+
# campaign.
|
68
|
+
operations += build_campaign_criterion_operations(campaign_operations)
|
69
|
+
|
70
|
+
# Create operations to create new ad groups.
|
71
|
+
ad_group_operations = build_ad_group_operations(
|
72
|
+
temp_id_generator, campaign_operations)
|
73
|
+
operations += ad_group_operations
|
74
|
+
|
75
|
+
# Create operations to create new ad group criteria (keywords).
|
76
|
+
operations += build_ad_group_criterion_operations(ad_group_operations)
|
77
|
+
|
78
|
+
# Create operations to create new ad group ads (text ads).
|
79
|
+
operations += build_ad_group_ad_operations(ad_group_operations)
|
80
|
+
|
81
|
+
# Use the batch_job_utils to upload all operations.
|
82
|
+
batch_job_utils.upload_operations(operations, upload_url)
|
83
|
+
puts "Uploaded %d operations for batch job with ID %d." %
|
84
|
+
[operations.size, batch_job[:id]]
|
85
|
+
|
86
|
+
# Poll for completion of the batch job using an exponential back off.
|
87
|
+
poll_attempts = 0
|
88
|
+
is_pending = true
|
89
|
+
selector = {
|
90
|
+
:fields => ['Id', 'Status', 'DownloadUrl', 'ProcessingErrors',
|
91
|
+
'ProgressStats'],
|
92
|
+
:predicates => [{
|
93
|
+
:field => 'Id',
|
94
|
+
:operator => 'IN',
|
95
|
+
:values => [batch_job[:id]]
|
96
|
+
}]
|
97
|
+
}
|
98
|
+
|
99
|
+
begin
|
100
|
+
sleep_seconds = 30 * (2 ** poll_attempts)
|
101
|
+
puts "Sleeping for %d seconds" % sleep_seconds
|
102
|
+
sleep(sleep_seconds)
|
103
|
+
|
104
|
+
batch_job = batch_job_srv.get(selector)[:entries].first
|
105
|
+
|
106
|
+
puts "Batch job ID %d has status '%s'." %
|
107
|
+
[batch_job[:id], batch_job[:status]]
|
108
|
+
|
109
|
+
poll_attempts += 1
|
110
|
+
is_pending = PENDING_STATUSES.include?(batch_job[:status])
|
111
|
+
end while is_pending and poll_attempts < MAX_POLL_ATTEMPTS
|
112
|
+
|
113
|
+
if is_pending
|
114
|
+
raise StandardError,
|
115
|
+
"Job is still in pending state after polling %d times." %
|
116
|
+
MAX_POLL_ATTEMPTS
|
117
|
+
end
|
118
|
+
|
119
|
+
unless batch_job[:processing_errors].nil?
|
120
|
+
batch_job[:processing_errors].each_with_index do |processing_error, i|
|
121
|
+
puts ("Processing error [%d]: errorType=%s, trigger=%s, errorString=%s" +
|
122
|
+
"fieldPath=%s, reason=%s") % [i, processing_error[:api_error_type],
|
123
|
+
processing_error[:trigger], processing_error[:error_string],
|
124
|
+
processing_error[:field_path], processing_error[:reason]]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
unless batch_job[:download_url].nil? or batch_job[:download_url][:url].nil?
|
129
|
+
mutate_response = batch_job_utils.get_job_results(
|
130
|
+
batch_job[:download_url][:url])
|
131
|
+
puts "Downloaded results from '%s':" % batch_job[:download_url][:url]
|
132
|
+
mutate_response.each do |mutate_result|
|
133
|
+
outcome = "FAILURE"
|
134
|
+
outcome = "SUCCESS" if mutate_result[:error_list].nil?
|
135
|
+
puts " Operation [%d] - %s" % [mutate_result[:index], outcome]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Custom class to generate temporary negative IDs for created entities to
|
141
|
+
# reference each other.
|
142
|
+
class TempIdGenerator
|
143
|
+
def initialize()
|
144
|
+
@counter = -1
|
145
|
+
end
|
146
|
+
|
147
|
+
def next()
|
148
|
+
ret = @counter
|
149
|
+
@counter -= 1
|
150
|
+
return ret
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def get_time_microseconds()
|
155
|
+
return (Time.now.to_f * 1000000).to_i
|
156
|
+
end
|
157
|
+
|
158
|
+
def build_budget_operation(temp_id_generator)
|
159
|
+
budget = {
|
160
|
+
:budget_id => temp_id_generator.next,
|
161
|
+
:name => "Interplanetary Cruise %d" % get_time_microseconds(),
|
162
|
+
:amount => {
|
163
|
+
:micro_amount => 50000000
|
164
|
+
},
|
165
|
+
:delivery_method => 'STANDARD'
|
166
|
+
}
|
167
|
+
budget_operation = {
|
168
|
+
# The xsi_type of the operation can usually be guessed by the API because
|
169
|
+
# a given service only handles one type of operation. However, batch jobs
|
170
|
+
# process operations of different types, so the xsi_type must always be
|
171
|
+
# explicitly defined for these operations.
|
172
|
+
:xsi_type => 'BudgetOperation',
|
173
|
+
:operator => 'ADD',
|
174
|
+
:operand => budget
|
175
|
+
}
|
176
|
+
return budget_operation
|
177
|
+
end
|
178
|
+
|
179
|
+
def build_campaign_operations(temp_id_generator, budget_operation)
|
180
|
+
budget_id = budget_operation[:operand][:budget_id]
|
181
|
+
|
182
|
+
operations = []
|
183
|
+
NUMBER_OF_CAMPAIGNS_TO_ADD.times do
|
184
|
+
campaign = {
|
185
|
+
:name => "Batch Campaign %s" % get_time_microseconds(),
|
186
|
+
:status => 'PAUSED',
|
187
|
+
:id => temp_id_generator.next,
|
188
|
+
:advertising_channel_type => 'SEARCH',
|
189
|
+
:budget => {
|
190
|
+
:budget_id => budget_id
|
191
|
+
},
|
192
|
+
:bidding_strategy_configuration => {
|
193
|
+
:bidding_strategy_type => 'MANUAL_CPC',
|
194
|
+
# You can optionally provide a bidding scheme in place of the type.
|
195
|
+
:bidding_scheme => {
|
196
|
+
:xsi_type => 'ManualCpcBiddingScheme',
|
197
|
+
:enhanced_cpc_enabled => false
|
198
|
+
}
|
199
|
+
}
|
200
|
+
}
|
201
|
+
operation = {
|
202
|
+
:xsi_type => 'CampaignOperation',
|
203
|
+
:operator => 'ADD',
|
204
|
+
:operand => campaign
|
205
|
+
}
|
206
|
+
operations << operation
|
207
|
+
end
|
208
|
+
|
209
|
+
return operations
|
210
|
+
end
|
211
|
+
|
212
|
+
def build_campaign_criterion_operations(campaign_operations)
|
213
|
+
operations = []
|
214
|
+
campaign_operations.each do |campaign_operation|
|
215
|
+
keyword = {
|
216
|
+
:xsi_type => 'Keyword',
|
217
|
+
:match_type => 'BROAD',
|
218
|
+
:text => 'venus'
|
219
|
+
}
|
220
|
+
negative_criterion = {
|
221
|
+
:xsi_type => 'NegativeCampaignCriterion',
|
222
|
+
:campaign_id => campaign_operation[:operand][:id],
|
223
|
+
:criterion => keyword
|
224
|
+
}
|
225
|
+
operation = {
|
226
|
+
:xsi_type => 'CampaignCriterionOperation',
|
227
|
+
:operator => 'ADD',
|
228
|
+
:operand => negative_criterion
|
229
|
+
}
|
230
|
+
operations << operation
|
231
|
+
end
|
232
|
+
|
233
|
+
return operations
|
234
|
+
end
|
235
|
+
|
236
|
+
def build_ad_group_operations(temp_id_generator, campaign_operations)
|
237
|
+
operations = []
|
238
|
+
campaign_operations.each do |campaign_operation|
|
239
|
+
NUMBER_OF_ADGROUPS_TO_ADD.times do
|
240
|
+
ad_group = {
|
241
|
+
:campaign_id => campaign_operation[:operand][:id],
|
242
|
+
:id => temp_id_generator.next,
|
243
|
+
:name => "Batch Ad Group %s" % get_time_microseconds(),
|
244
|
+
:bidding_strategy_configuration => {
|
245
|
+
:bids => [
|
246
|
+
{
|
247
|
+
:xsi_type => 'CpcBid',
|
248
|
+
:bid => {:micro_amount => 10000000}
|
249
|
+
}
|
250
|
+
]
|
251
|
+
}
|
252
|
+
}
|
253
|
+
operation = {
|
254
|
+
:xsi_type => 'AdGroupOperation',
|
255
|
+
:operator => 'ADD',
|
256
|
+
:operand => ad_group
|
257
|
+
}
|
258
|
+
operations << operation
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
return operations
|
263
|
+
end
|
264
|
+
|
265
|
+
def build_ad_group_criterion_operations(ad_group_operations)
|
266
|
+
operations = []
|
267
|
+
ad_group_operations.each do |ad_group_operation|
|
268
|
+
NUMBER_OF_KEYWORDS_TO_ADD.times do |i|
|
269
|
+
text = "mars%d" % i
|
270
|
+
|
271
|
+
# Make 50% of keywords invalid to demonstrate error handling.
|
272
|
+
text = text + "!!!" if i % 2 == 0
|
273
|
+
keyword = {
|
274
|
+
:xsi_type => 'Keyword',
|
275
|
+
:text => text,
|
276
|
+
:match_type => 'BROAD'
|
277
|
+
}
|
278
|
+
biddable_criterion = {
|
279
|
+
:xsi_type => 'BiddableAdGroupCriterion',
|
280
|
+
:ad_group_id => ad_group_operation[:operand][:id],
|
281
|
+
:criterion => keyword
|
282
|
+
}
|
283
|
+
operation = {
|
284
|
+
:xsi_type => 'AdGroupCriterionOperation',
|
285
|
+
:operator => 'ADD',
|
286
|
+
:operand => biddable_criterion
|
287
|
+
}
|
288
|
+
operations << operation
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
return operations
|
293
|
+
end
|
294
|
+
|
295
|
+
def build_ad_group_ad_operations(ad_group_operations)
|
296
|
+
operations = []
|
297
|
+
ad_group_operations.each do |ad_group_operation|
|
298
|
+
text_ad = {
|
299
|
+
:xsi_type => 'ExpandedTextAd',
|
300
|
+
:headline_part1 => 'Luxury Cruise to Mars',
|
301
|
+
:headling_part2 => 'Visit the Red Planet in style.',
|
302
|
+
:description => 'Low-gravity fun for everyone!',
|
303
|
+
:final_urls => ['http://www.example.com/1']
|
304
|
+
}
|
305
|
+
ad_group_ad = {
|
306
|
+
:ad_group_id => ad_group_operation[:operand][:id],
|
307
|
+
:ad => text_ad
|
308
|
+
}
|
309
|
+
operation = {
|
310
|
+
:xsi_type => 'AdGroupAdOperation',
|
311
|
+
:operator => 'ADD',
|
312
|
+
:operand => ad_group_ad
|
313
|
+
}
|
314
|
+
operations << operation
|
315
|
+
end
|
316
|
+
|
317
|
+
return operations
|
318
|
+
end
|
319
|
+
|
320
|
+
if __FILE__ == $0
|
321
|
+
API_VERSION = :v201609
|
322
|
+
NUMBER_OF_CAMPAIGNS_TO_ADD = 2
|
323
|
+
NUMBER_OF_ADGROUPS_TO_ADD = 2
|
324
|
+
NUMBER_OF_KEYWORDS_TO_ADD = 5
|
325
|
+
MAX_POLL_ATTEMPTS = 5
|
326
|
+
PENDING_STATUSES = ['ACTIVE', 'AWAITING_FILE', 'CANCELING']
|
327
|
+
|
328
|
+
begin
|
329
|
+
add_complete_campaigns_using_batch_job()
|
330
|
+
|
331
|
+
# Authorization error.
|
332
|
+
rescue AdsCommon::Errors::OAuth2VerificationRequired => e
|
333
|
+
puts "Authorization credentials are not valid. Edit adwords_api.yml for " +
|
334
|
+
"OAuth2 client ID and secret and run misc/setup_oauth2.rb example " +
|
335
|
+
"to retrieve and store OAuth2 tokens."
|
336
|
+
puts "See this wiki page for more details:\n\n " +
|
337
|
+
'https://github.com/googleads/google-api-ads-ruby/wiki/OAuth2'
|
338
|
+
|
339
|
+
# HTTP errors.
|
340
|
+
rescue AdsCommon::Errors::HttpError => e
|
341
|
+
puts "HTTP Error: %s" % e
|
342
|
+
|
343
|
+
# API errors.
|
344
|
+
rescue AdwordsApi::Errors::ApiException => e
|
345
|
+
puts "Message: %s" % e.message
|
346
|
+
puts 'Errors:'
|
347
|
+
e.errors.each_with_index do |error, index|
|
348
|
+
puts "\tError [%d]:" % (index + 1)
|
349
|
+
error.each do |field, value|
|
350
|
+
puts "\t\t%s: %s" % [field, value]
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Encoding: utf-8
|
3
|
+
#
|
4
|
+
# Copyright:: Copyright 2016, Google Inc. All Rights Reserved.
|
5
|
+
#
|
6
|
+
# License:: Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
15
|
+
# implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
# This example illustrates how to create a draft and access its associated
|
20
|
+
# draft campaign.
|
21
|
+
#
|
22
|
+
# See the Campaign Drafts and Experiments guide for more information:
|
23
|
+
# https://developers.google.com/adwords/api/docs/guides/campaign-drafts-experiments
|
24
|
+
|
25
|
+
require 'adwords_api'
|
26
|
+
require 'date'
|
27
|
+
|
28
|
+
def add_draft(base_campaign_id)
|
29
|
+
# AdwordsApi::Api will read a config file from ENV['HOME']/adwords_api.yml
|
30
|
+
# when called without parameters.
|
31
|
+
adwords = AdwordsApi::Api.new
|
32
|
+
|
33
|
+
# To enable logging of SOAP requests, set the log_level value to 'DEBUG' in
|
34
|
+
# the configuration file or provide your own logger:
|
35
|
+
# adwords.logger = Logger.new('adwords_xml.log')
|
36
|
+
|
37
|
+
draft_srv = adwords.service(:DraftService, API_VERSION)
|
38
|
+
|
39
|
+
draft = {
|
40
|
+
:base_campaign_id => base_campaign_id,
|
41
|
+
:draft_name => 'Test Draft #%d' % (Time.new.to_f * 1000).to_i
|
42
|
+
}
|
43
|
+
draft_operation = {:operator => 'ADD', :operand => draft}
|
44
|
+
|
45
|
+
draft_result = draft_srv.mutate([draft_operation])
|
46
|
+
|
47
|
+
draft = draft_result[:value].first
|
48
|
+
draft_id = draft[:draft_id]
|
49
|
+
draft_campaign_id = draft[:draft_campaign_id]
|
50
|
+
|
51
|
+
puts "Draft with id %d and base campaign %d and draft campaign %d created" %
|
52
|
+
[draft_id, draft[:base_campaign_id], draft_campaign_id]
|
53
|
+
|
54
|
+
# Once the draft is created, you can modify the draft campaign as if it
|
55
|
+
# were a real campaign. For example, you may add criteria, adjust bids,
|
56
|
+
# or even include additional ads. Adding a criterion is shown here.
|
57
|
+
campaign_criterion_srv =
|
58
|
+
adwords.service(:CampaignCriterionService, API_VERSION)
|
59
|
+
|
60
|
+
criterion = {
|
61
|
+
:xsi_type => 'Language',
|
62
|
+
:id => 1003 # Spanish
|
63
|
+
}
|
64
|
+
|
65
|
+
criterion_operation = {
|
66
|
+
# Make sure to use the draft_campaign_id when modifying the virtual draft
|
67
|
+
# campaign.
|
68
|
+
:operator => 'ADD',
|
69
|
+
:operand => {
|
70
|
+
:campaign_id => draft_campaign_id,
|
71
|
+
:criterion => criterion
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
criterion_result = campaign_criterion_srv.mutate([criterion_operation])
|
76
|
+
|
77
|
+
criterion = criterion_result[:value].first
|
78
|
+
|
79
|
+
puts "Draft updated to include criteria in campaign %d" % draft_campaign_id
|
80
|
+
end
|
81
|
+
|
82
|
+
if __FILE__ == $0
|
83
|
+
API_VERSION = :v201609
|
84
|
+
|
85
|
+
begin
|
86
|
+
base_campaign_id = 'INSERT_BASE_CAMPAIGN_ID_HERE'.to_i
|
87
|
+
|
88
|
+
add_draft(base_campaign_id)
|
89
|
+
|
90
|
+
# Authorization error.
|
91
|
+
rescue AdsCommon::Errors::OAuth2VerificationRequired => e
|
92
|
+
puts "Authorization credentials are not valid. Edit adwords_api.yml for " +
|
93
|
+
"OAuth2 client ID and secret and run misc/setup_oauth2.rb example " +
|
94
|
+
"to retrieve and store OAuth2 tokens."
|
95
|
+
puts "See this wiki page for more details:\n\n " +
|
96
|
+
'https://github.com/googleads/google-api-ads-ruby/wiki/OAuth2'
|
97
|
+
|
98
|
+
# HTTP errors.
|
99
|
+
rescue AdsCommon::Errors::HttpError => e
|
100
|
+
puts "HTTP Error: %s" % e
|
101
|
+
|
102
|
+
# API errors.
|
103
|
+
rescue AdwordsApi::Errors::ApiException => e
|
104
|
+
puts "Message: %s" % e.message
|
105
|
+
puts 'Errors:'
|
106
|
+
e.errors.each_with_index do |error, index|
|
107
|
+
puts "\tError [%d]:" % (index + 1)
|
108
|
+
error.each do |field, value|
|
109
|
+
puts "\t\t%s: %s" % [field, value]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|