google-adwords-api 0.18.0 → 0.18.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 +8 -0
- data/examples/v201509/basic_operations/add_ad_groups.rb +4 -2
- data/examples/v201509/remarketing/add_crm_based_user_list.rb +2 -4
- data/examples/v201509/{advanced_operations → remarketing}/upload_offline_conversions.rb +6 -21
- data/examples/v201601/account_management/create_account.rb +88 -0
- data/examples/v201601/account_management/get_account_changes.rb +139 -0
- data/examples/v201601/account_management/get_account_hierarchy.rb +132 -0
- data/examples/v201601/advanced_operations/add_ad_customizers.rb +184 -0
- data/examples/v201601/advanced_operations/add_ad_group_bid_modifier.rb +101 -0
- data/examples/v201601/advanced_operations/add_click_to_download_ad.rb +133 -0
- data/examples/v201601/advanced_operations/add_html5_ad.rb +137 -0
- data/examples/v201601/advanced_operations/add_keywords_using_incremental_batch_job.rb +179 -0
- data/examples/v201601/advanced_operations/add_text_ad_with_upgraded_urls.rb +134 -0
- data/examples/v201601/advanced_operations/create_and_attach_shared_keyword_set.rb +141 -0
- data/examples/v201601/advanced_operations/find_and_remove_criteria_from_shared_set.rb +174 -0
- data/examples/v201601/advanced_operations/get_ad_group_bid_modifiers.rb +102 -0
- data/examples/v201601/advanced_operations/use_shared_bidding_strategy.rb +147 -0
- data/examples/v201601/basic_operations/add_ad_groups.rb +142 -0
- data/examples/v201601/basic_operations/add_campaigns.rb +139 -0
- data/examples/v201601/basic_operations/add_keywords.rb +114 -0
- data/examples/v201601/basic_operations/add_text_ads.rb +109 -0
- data/examples/v201601/basic_operations/get_ad_groups.rb +102 -0
- data/examples/v201601/basic_operations/get_campaigns.rb +97 -0
- data/examples/v201601/basic_operations/get_campaigns_with_awql.rb +89 -0
- data/examples/v201601/basic_operations/get_keywords.rb +109 -0
- data/examples/v201601/basic_operations/get_text_ads.rb +110 -0
- data/examples/v201601/basic_operations/pause_ad.rb +88 -0
- data/examples/v201601/basic_operations/remove_ad.rb +89 -0
- data/examples/v201601/basic_operations/remove_ad_group.rb +85 -0
- data/examples/v201601/basic_operations/remove_campaign.rb +87 -0
- data/examples/v201601/basic_operations/remove_keyword.rb +94 -0
- data/examples/v201601/basic_operations/update_ad_group.rb +85 -0
- data/examples/v201601/basic_operations/update_campaign.rb +86 -0
- data/examples/v201601/basic_operations/update_keyword.rb +106 -0
- data/examples/v201601/campaign_management/add_campaign_labels.rb +82 -0
- data/examples/v201601/campaign_management/add_complete_campaigns_using_batch_job.rb +356 -0
- data/examples/v201601/campaign_management/add_experiment.rb +162 -0
- data/examples/v201601/campaign_management/add_keywords_in_bulk.rb +153 -0
- data/examples/v201601/campaign_management/get_all_disapproved_ads.rb +97 -0
- data/examples/v201601/campaign_management/get_all_disapproved_ads_with_awql.rb +89 -0
- data/examples/v201601/campaign_management/get_campaigns_by_label.rb +108 -0
- data/examples/v201601/campaign_management/promote_experiment.rb +81 -0
- data/examples/v201601/campaign_management/set_ad_parameters.rb +118 -0
- data/examples/v201601/campaign_management/set_criterion_bid_modifier.rb +104 -0
- data/examples/v201601/campaign_management/validate_text_ad.rb +110 -0
- data/examples/v201601/error_handling/handle_partial_failures.rb +130 -0
- data/examples/v201601/error_handling/handle_policy_violation_error.rb +141 -0
- data/examples/v201601/extensions/add_google_my_business_location_extensions.rb +193 -0
- data/examples/v201601/extensions/add_site_links.rb +164 -0
- data/examples/v201601/extensions/add_site_links_using_feeds.rb +281 -0
- data/examples/v201601/migration/migrate_to_extension_settings.rb +386 -0
- data/examples/v201601/migration/upgrade_ad_url.rb +93 -0
- data/examples/v201601/misc/get_all_images_and_videos.rb +104 -0
- data/examples/v201601/misc/setup_oauth2.rb +84 -0
- data/examples/v201601/misc/upload_image.rb +93 -0
- data/examples/v201601/misc/upload_media_bundle.rb +90 -0
- data/examples/v201601/misc/use_oauth2_jwt.rb +93 -0
- data/examples/v201601/misc/use_runtime_config.rb +92 -0
- data/examples/v201601/optimization/estimate_keyword_traffic.rb +146 -0
- data/examples/v201601/optimization/get_keyword_bid_simulations.rb +95 -0
- data/examples/v201601/optimization/get_keyword_ideas.rb +126 -0
- data/examples/v201601/remarketing/add_audience.rb +118 -0
- data/examples/v201601/remarketing/add_conversion_tracker.rb +97 -0
- data/examples/v201601/remarketing/add_crm_based_user_list.rb +119 -0
- data/examples/v201601/remarketing/add_rule_based_user_lists.rb +167 -0
- data/examples/v201601/remarketing/upload_offline_conversions.rb +98 -0
- data/examples/v201601/reporting/download_criteria_report.rb +92 -0
- data/examples/v201601/reporting/download_criteria_report_with_awql.rb +93 -0
- data/examples/v201601/reporting/get_report_fields.rb +75 -0
- data/examples/v201601/reporting/parallel_report_download.rb +166 -0
- data/examples/v201601/reporting/stream_criteria_report_results.rb +97 -0
- data/examples/v201601/shopping_campaigns/add_product_partition_tree.rb +267 -0
- data/examples/v201601/shopping_campaigns/add_product_scope.rb +129 -0
- data/examples/v201601/shopping_campaigns/add_shopping_campaign.rb +129 -0
- data/examples/v201601/shopping_campaigns/get_product_category_taxonomy.rb +115 -0
- data/examples/v201601/targeting/add_campaign_targeting_criteria.rb +180 -0
- data/examples/v201601/targeting/add_demographic_targeting_criteria.rb +112 -0
- data/examples/v201601/targeting/get_campaign_targeting_criteria.rb +106 -0
- data/examples/v201601/targeting/get_targetable_languages_and_carriers.rb +89 -0
- data/examples/v201601/targeting/lookup_location.rb +108 -0
- data/lib/adwords_api/api_config.rb +90 -4
- data/lib/adwords_api/batch_job_utils.rb +29 -17
- data/lib/adwords_api/incremental_upload_helper.rb +5 -1
- data/lib/adwords_api/report_stream.rb +7 -8
- data/lib/adwords_api/report_utils.rb +4 -4
- data/lib/adwords_api/v201601/account_label_service.rb +46 -0
- data/lib/adwords_api/v201601/account_label_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/ad_customizer_feed_service.rb +46 -0
- data/lib/adwords_api/v201601/ad_customizer_feed_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/ad_group_ad_service.rb +70 -0
- data/lib/adwords_api/v201601/ad_group_ad_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/ad_group_bid_modifier_service.rb +54 -0
- data/lib/adwords_api/v201601/ad_group_bid_modifier_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/ad_group_criterion_service.rb +62 -0
- data/lib/adwords_api/v201601/ad_group_criterion_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/ad_group_extension_setting_service.rb +54 -0
- data/lib/adwords_api/v201601/ad_group_extension_setting_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/ad_group_feed_service.rb +54 -0
- data/lib/adwords_api/v201601/ad_group_feed_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/ad_group_service.rb +62 -0
- data/lib/adwords_api/v201601/ad_group_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/ad_param_service.rb +46 -0
- data/lib/adwords_api/v201601/ad_param_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/adwords_user_list_service.rb +54 -0
- data/lib/adwords_api/v201601/adwords_user_list_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/batch_job_service.rb +54 -0
- data/lib/adwords_api/v201601/batch_job_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/bidding_strategy_service.rb +54 -0
- data/lib/adwords_api/v201601/bidding_strategy_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/budget_order_service.rb +54 -0
- data/lib/adwords_api/v201601/budget_order_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/budget_service.rb +54 -0
- data/lib/adwords_api/v201601/budget_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/campaign_criterion_service.rb +54 -0
- data/lib/adwords_api/v201601/campaign_criterion_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/campaign_extension_setting_service.rb +54 -0
- data/lib/adwords_api/v201601/campaign_extension_setting_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/campaign_feed_service.rb +54 -0
- data/lib/adwords_api/v201601/campaign_feed_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/campaign_service.rb +62 -0
- data/lib/adwords_api/v201601/campaign_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/campaign_shared_set_service.rb +54 -0
- data/lib/adwords_api/v201601/campaign_shared_set_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/constant_data_service.rb +110 -0
- data/lib/adwords_api/v201601/constant_data_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/conversion_tracker_service.rb +54 -0
- data/lib/adwords_api/v201601/conversion_tracker_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/customer_extension_setting_service.rb +54 -0
- data/lib/adwords_api/v201601/customer_extension_setting_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/customer_feed_service.rb +54 -0
- data/lib/adwords_api/v201601/customer_feed_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/customer_service.rb +54 -0
- data/lib/adwords_api/v201601/customer_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/customer_sync_service.rb +38 -0
- data/lib/adwords_api/v201601/customer_sync_service_registry.rb +47 -0
- data/lib/adwords_api/v201601/data_service.rb +78 -0
- data/lib/adwords_api/v201601/data_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/experiment_service.rb +46 -0
- data/lib/adwords_api/v201601/experiment_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/feed_item_service.rb +54 -0
- data/lib/adwords_api/v201601/feed_item_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/feed_mapping_service.rb +54 -0
- data/lib/adwords_api/v201601/feed_mapping_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/feed_service.rb +54 -0
- data/lib/adwords_api/v201601/feed_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/label_service.rb +54 -0
- data/lib/adwords_api/v201601/label_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/location_criterion_service.rb +46 -0
- data/lib/adwords_api/v201601/location_criterion_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/managed_customer_service.rb +78 -0
- data/lib/adwords_api/v201601/managed_customer_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/media_service.rb +54 -0
- data/lib/adwords_api/v201601/media_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/mutate_job_service.rb +54 -0
- data/lib/adwords_api/v201601/mutate_job_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/offline_conversion_feed_service.rb +38 -0
- data/lib/adwords_api/v201601/offline_conversion_feed_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/report_definition_service.rb +38 -0
- data/lib/adwords_api/v201601/report_definition_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/shared_criterion_service.rb +54 -0
- data/lib/adwords_api/v201601/shared_criterion_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/shared_set_service.rb +54 -0
- data/lib/adwords_api/v201601/shared_set_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/targeting_idea_service.rb +38 -0
- data/lib/adwords_api/v201601/targeting_idea_service_registry.rb +46 -0
- data/lib/adwords_api/v201601/traffic_estimator_service.rb +38 -0
- data/lib/adwords_api/v201601/traffic_estimator_service_registry.rb +46 -0
- data/lib/adwords_api/version.rb +1 -1
- data/test/adwords_api/test_batch_job_utils.rb +11 -2
- metadata +163 -5
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# Encoding: utf-8
|
|
3
|
+
#
|
|
4
|
+
# Copyright:: Copyright 2011, 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 updates the bid of a keyword. To create a keyword, run
|
|
20
|
+
# add_keywords.rb.
|
|
21
|
+
|
|
22
|
+
require 'adwords_api'
|
|
23
|
+
|
|
24
|
+
def update_keyword(ad_group_id, criterion_id)
|
|
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
|
+
ad_group_criterion_srv =
|
|
34
|
+
adwords.service(:AdGroupCriterionService, API_VERSION)
|
|
35
|
+
|
|
36
|
+
# Prepare for updating a keyword.
|
|
37
|
+
operation = {
|
|
38
|
+
:operator => 'SET',
|
|
39
|
+
:operand => {
|
|
40
|
+
# The 'xsi_type' field allows you to specify the xsi:type of the object
|
|
41
|
+
# being created. It's only necessary when you must provide an explicit
|
|
42
|
+
# type that the client library can't infer.
|
|
43
|
+
:xsi_type => 'BiddableAdGroupCriterion',
|
|
44
|
+
:ad_group_id => ad_group_id,
|
|
45
|
+
:criterion => {
|
|
46
|
+
:id => criterion_id
|
|
47
|
+
},
|
|
48
|
+
:bidding_strategy_configuration => {
|
|
49
|
+
:bids => [
|
|
50
|
+
{
|
|
51
|
+
:xsi_type => 'CpcBid',
|
|
52
|
+
:bid => {:micro_amount => 1000000}
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Update criterion.
|
|
60
|
+
response = ad_group_criterion_srv.mutate([operation])
|
|
61
|
+
if response and response[:value]
|
|
62
|
+
ad_group_criterion = response[:value].first
|
|
63
|
+
puts "Keyword ID %d was successfully updated, current bids are:" %
|
|
64
|
+
ad_group_criterion[:criterion][:id]
|
|
65
|
+
ad_group_criterion[:bidding_strategy_configuration][:bids].each do |bid|
|
|
66
|
+
puts "\tType: '%s', value: %d" %
|
|
67
|
+
[bid[:bids_type], bid[:bid][:micro_amount]]
|
|
68
|
+
end
|
|
69
|
+
else
|
|
70
|
+
puts 'No keywords were updated.'
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
if __FILE__ == $0
|
|
75
|
+
API_VERSION = :v201601
|
|
76
|
+
|
|
77
|
+
begin
|
|
78
|
+
# IDs of a criterion to update and its ad group.
|
|
79
|
+
ad_group_id = 'INSERT_AD_GROUP_ID_HERE'.to_i
|
|
80
|
+
criterion_id = 'INSERT_CRITERION_ID_HERE'.to_i
|
|
81
|
+
update_keyword(ad_group_id, criterion_id)
|
|
82
|
+
|
|
83
|
+
# Authorization error.
|
|
84
|
+
rescue AdsCommon::Errors::OAuth2VerificationRequired => e
|
|
85
|
+
puts "Authorization credentials are not valid. Edit adwords_api.yml for " +
|
|
86
|
+
"OAuth2 client ID and secret and run misc/setup_oauth2.rb example " +
|
|
87
|
+
"to retrieve and store OAuth2 tokens."
|
|
88
|
+
puts "See this wiki page for more details:\n\n " +
|
|
89
|
+
'https://github.com/googleads/google-api-ads-ruby/wiki/OAuth2'
|
|
90
|
+
|
|
91
|
+
# HTTP errors.
|
|
92
|
+
rescue AdsCommon::Errors::HttpError => e
|
|
93
|
+
puts "HTTP Error: %s" % e
|
|
94
|
+
|
|
95
|
+
# API errors.
|
|
96
|
+
rescue AdwordsApi::Errors::ApiException => e
|
|
97
|
+
puts "Message: %s" % e.message
|
|
98
|
+
puts 'Errors:'
|
|
99
|
+
e.errors.each_with_index do |error, index|
|
|
100
|
+
puts "\tError [%d]:" % (index + 1)
|
|
101
|
+
error.each do |field, value|
|
|
102
|
+
puts "\t\t%s: %s" % [field, value]
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# Encoding: utf-8
|
|
3
|
+
#
|
|
4
|
+
# Copyright:: Copyright 2014, 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 adds a label to multiple campaigns.
|
|
20
|
+
|
|
21
|
+
require 'adwords_api'
|
|
22
|
+
|
|
23
|
+
def add_campaign_labels(campaign_ids, label_id)
|
|
24
|
+
# AdwordsApi::Api will read a config file from ENV['HOME']/adwords_api.yml
|
|
25
|
+
# when called without parameters.
|
|
26
|
+
adwords = AdwordsApi::Api.new
|
|
27
|
+
|
|
28
|
+
# To enable logging of SOAP requests, set the log_level value to 'DEBUG' in
|
|
29
|
+
# the configuration file or provide your own logger:
|
|
30
|
+
# adwords.logger = Logger.new('adwords_xml.log')
|
|
31
|
+
|
|
32
|
+
campaign_srv = adwords.service(:CampaignService, API_VERSION)
|
|
33
|
+
|
|
34
|
+
operations = campaign_ids.map do |campaign_id|
|
|
35
|
+
{
|
|
36
|
+
:operator => 'ADD',
|
|
37
|
+
:operand => {:campaign_id => campaign_id, :label_id => label_id}
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
response = campaign_srv.mutate_label(operations)
|
|
42
|
+
if response and response[:value]
|
|
43
|
+
response[:value].each do |campaign_label|
|
|
44
|
+
puts "Campaign label for campaign ID %d and label ID %d was added.\n" %
|
|
45
|
+
[campaign_label[:campaign_id], campaign_label[:label_id]]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
if __FILE__ == $0
|
|
51
|
+
API_VERSION = :v201601
|
|
52
|
+
|
|
53
|
+
begin
|
|
54
|
+
campaign_id_1 = 'INSERT_CAMPAIGN_ID_1_HERE'.to_i
|
|
55
|
+
campaign_id_2 = 'INSERT_CAMPAIGN_ID_2_HERE'.to_i
|
|
56
|
+
label_id = 'INSERT_LABEL_ID_HERE'.to_i
|
|
57
|
+
add_campaign_labels([campaign_id_1, campaign_id_2], label_id)
|
|
58
|
+
|
|
59
|
+
# Authorization error.
|
|
60
|
+
rescue AdsCommon::Errors::OAuth2VerificationRequired => e
|
|
61
|
+
puts "Authorization credentials are not valid. Edit adwords_api.yml for " +
|
|
62
|
+
"OAuth2 client ID and secret and run misc/setup_oauth2.rb example " +
|
|
63
|
+
"to retrieve and store OAuth2 tokens."
|
|
64
|
+
puts "See this wiki page for more details:\n\n " +
|
|
65
|
+
'https://github.com/googleads/google-api-ads-ruby/wiki/OAuth2'
|
|
66
|
+
|
|
67
|
+
# HTTP errors.
|
|
68
|
+
rescue AdsCommon::Errors::HttpError => e
|
|
69
|
+
puts "HTTP Error: %s" % e
|
|
70
|
+
|
|
71
|
+
# API errors.
|
|
72
|
+
rescue AdwordsApi::Errors::ApiException => e
|
|
73
|
+
puts "Message: %s" % e.message
|
|
74
|
+
puts 'Errors:'
|
|
75
|
+
e.errors.each_with_index do |error, index|
|
|
76
|
+
puts "\tError [%d]:" % (index + 1)
|
|
77
|
+
error.each do |field, value|
|
|
78
|
+
puts "\t\t%s: %s" % [field, value]
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,356 @@
|
|
|
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
|
+
:period => 'DAILY'
|
|
167
|
+
}
|
|
168
|
+
budget_operation = {
|
|
169
|
+
# The xsi_type of the operation can usually be guessed by the API because
|
|
170
|
+
# a given service only handles one type of operation. However, batch jobs
|
|
171
|
+
# process operations of different types, so the xsi_type must always be
|
|
172
|
+
# explicitly defined for these operations.
|
|
173
|
+
:xsi_type => 'BudgetOperation',
|
|
174
|
+
:operator => 'ADD',
|
|
175
|
+
:operand => budget
|
|
176
|
+
}
|
|
177
|
+
return budget_operation
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def build_campaign_operations(temp_id_generator, budget_operation)
|
|
181
|
+
budget_id = budget_operation[:operand][:budget_id]
|
|
182
|
+
|
|
183
|
+
operations = []
|
|
184
|
+
NUMBER_OF_CAMPAIGNS_TO_ADD.times do
|
|
185
|
+
campaign = {
|
|
186
|
+
:name => "Batch Campaign %s" % get_time_microseconds(),
|
|
187
|
+
:status => 'PAUSED',
|
|
188
|
+
:id => temp_id_generator.next,
|
|
189
|
+
:advertising_channel_type => 'SEARCH',
|
|
190
|
+
:budget => {
|
|
191
|
+
:budget_id => budget_id
|
|
192
|
+
},
|
|
193
|
+
:bidding_strategy_configuration => {
|
|
194
|
+
:bidding_strategy_type => 'MANUAL_CPC',
|
|
195
|
+
# You can optionally provide a bidding scheme in place of the type.
|
|
196
|
+
:bidding_scheme => {
|
|
197
|
+
:xsi_type => 'ManualCpcBiddingScheme',
|
|
198
|
+
:enhanced_cpc_enabled => false
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
operation = {
|
|
203
|
+
:xsi_type => 'CampaignOperation',
|
|
204
|
+
:operator => 'ADD',
|
|
205
|
+
:operand => campaign
|
|
206
|
+
}
|
|
207
|
+
operations << operation
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
return operations
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def build_campaign_criterion_operations(campaign_operations)
|
|
214
|
+
operations = []
|
|
215
|
+
campaign_operations.each do |campaign_operation|
|
|
216
|
+
keyword = {
|
|
217
|
+
:xsi_type => 'Keyword',
|
|
218
|
+
:match_type => 'BROAD',
|
|
219
|
+
:text => 'venus'
|
|
220
|
+
}
|
|
221
|
+
negative_criterion = {
|
|
222
|
+
:xsi_type => 'NegativeCampaignCriterion',
|
|
223
|
+
:campaign_id => campaign_operation[:operand][:id],
|
|
224
|
+
:criterion => keyword
|
|
225
|
+
}
|
|
226
|
+
operation = {
|
|
227
|
+
:xsi_type => 'CampaignCriterionOperation',
|
|
228
|
+
:operator => 'ADD',
|
|
229
|
+
:operand => negative_criterion
|
|
230
|
+
}
|
|
231
|
+
operations << operation
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
return operations
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def build_ad_group_operations(temp_id_generator, campaign_operations)
|
|
238
|
+
operations = []
|
|
239
|
+
campaign_operations.each do |campaign_operation|
|
|
240
|
+
NUMBER_OF_ADGROUPS_TO_ADD.times do
|
|
241
|
+
ad_group = {
|
|
242
|
+
:campaign_id => campaign_operation[:operand][:id],
|
|
243
|
+
:id => temp_id_generator.next,
|
|
244
|
+
:name => "Batch Ad Group %s" % get_time_microseconds(),
|
|
245
|
+
:bidding_strategy_configuration => {
|
|
246
|
+
:bids => [
|
|
247
|
+
{
|
|
248
|
+
:xsi_type => 'CpcBid',
|
|
249
|
+
:bid => {:micro_amount => 10000000}
|
|
250
|
+
}
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
operation = {
|
|
255
|
+
:xsi_type => 'AdGroupOperation',
|
|
256
|
+
:operator => 'ADD',
|
|
257
|
+
:operand => ad_group
|
|
258
|
+
}
|
|
259
|
+
operations << operation
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
return operations
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def build_ad_group_criterion_operations(ad_group_operations)
|
|
267
|
+
operations = []
|
|
268
|
+
ad_group_operations.each do |ad_group_operation|
|
|
269
|
+
NUMBER_OF_KEYWORDS_TO_ADD.times do |i|
|
|
270
|
+
text = "mars%d" % i
|
|
271
|
+
|
|
272
|
+
# Make 50% of keywords invalid to demonstrate error handling.
|
|
273
|
+
text = text + "!!!" if i % 2 == 0
|
|
274
|
+
keyword = {
|
|
275
|
+
:xsi_type => 'Keyword',
|
|
276
|
+
:text => text,
|
|
277
|
+
:match_type => 'BROAD'
|
|
278
|
+
}
|
|
279
|
+
biddable_criterion = {
|
|
280
|
+
:xsi_type => 'BiddableAdGroupCriterion',
|
|
281
|
+
:ad_group_id => ad_group_operation[:operand][:id],
|
|
282
|
+
:criterion => keyword
|
|
283
|
+
}
|
|
284
|
+
operation = {
|
|
285
|
+
:xsi_type => 'AdGroupCriterionOperation',
|
|
286
|
+
:operator => 'ADD',
|
|
287
|
+
:operand => biddable_criterion
|
|
288
|
+
}
|
|
289
|
+
operations << operation
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
return operations
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def build_ad_group_ad_operations(ad_group_operations)
|
|
297
|
+
operations = []
|
|
298
|
+
ad_group_operations.each do |ad_group_operation|
|
|
299
|
+
text_ad = {
|
|
300
|
+
:xsi_type => 'TextAd',
|
|
301
|
+
:headline => 'Luxury Cruise to Mars',
|
|
302
|
+
:description1 => 'Visit the Red Planet in style.',
|
|
303
|
+
:description2 => 'Low-gravity fun for everyone!',
|
|
304
|
+
:display_url => 'www.example.com',
|
|
305
|
+
:final_urls => ['http://www.example.com/1']
|
|
306
|
+
}
|
|
307
|
+
ad_group_ad = {
|
|
308
|
+
:ad_group_id => ad_group_operation[:operand][:id],
|
|
309
|
+
:ad => text_ad
|
|
310
|
+
}
|
|
311
|
+
operation = {
|
|
312
|
+
:xsi_type => 'AdGroupAdOperation',
|
|
313
|
+
:operator => 'ADD',
|
|
314
|
+
:operand => ad_group_ad
|
|
315
|
+
}
|
|
316
|
+
operations << operation
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
return operations
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
if __FILE__ == $0
|
|
323
|
+
API_VERSION = :v201601
|
|
324
|
+
NUMBER_OF_CAMPAIGNS_TO_ADD = 2
|
|
325
|
+
NUMBER_OF_ADGROUPS_TO_ADD = 2
|
|
326
|
+
NUMBER_OF_KEYWORDS_TO_ADD = 5
|
|
327
|
+
MAX_POLL_ATTEMPTS = 5
|
|
328
|
+
PENDING_STATUSES = ['ACTIVE', 'AWAITING_FILE']
|
|
329
|
+
|
|
330
|
+
begin
|
|
331
|
+
add_complete_campaigns_using_batch_job()
|
|
332
|
+
|
|
333
|
+
# Authorization error.
|
|
334
|
+
rescue AdsCommon::Errors::OAuth2VerificationRequired => e
|
|
335
|
+
puts "Authorization credentials are not valid. Edit adwords_api.yml for " +
|
|
336
|
+
"OAuth2 client ID and secret and run misc/setup_oauth2.rb example " +
|
|
337
|
+
"to retrieve and store OAuth2 tokens."
|
|
338
|
+
puts "See this wiki page for more details:\n\n " +
|
|
339
|
+
'https://github.com/googleads/google-api-ads-ruby/wiki/OAuth2'
|
|
340
|
+
|
|
341
|
+
# HTTP errors.
|
|
342
|
+
rescue AdsCommon::Errors::HttpError => e
|
|
343
|
+
puts "HTTP Error: %s" % e
|
|
344
|
+
|
|
345
|
+
# API errors.
|
|
346
|
+
rescue AdwordsApi::Errors::ApiException => e
|
|
347
|
+
puts "Message: %s" % e.message
|
|
348
|
+
puts 'Errors:'
|
|
349
|
+
e.errors.each_with_index do |error, index|
|
|
350
|
+
puts "\tError [%d]:" % (index + 1)
|
|
351
|
+
error.each do |field, value|
|
|
352
|
+
puts "\t\t%s: %s" % [field, value]
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
end
|