Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Adding a full example of how to create a Responsive Search Ad (with keywords and geo targeting) #715

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Feb 8, 2023

Conversation

fblascogarma
Copy link
Contributor

This example shows how to create a complete Responsive Search ad.

Includes creation of: budget, campaign, ad group, ad group ad,
keywords, geo targeting, and image extensions.

@fblascogarma fblascogarma requested a review from a team as a code owner October 24, 2022 22:31
@laurachevalier4 laurachevalier4 requested review from bobhancock and removed request for laurachevalier4 October 25, 2022 14:05
@BenRKarl BenRKarl requested review from BenRKarl and removed request for wihl December 6, 2022 14:56
@@ -0,0 +1,541 @@
#!/usr/bin/env python
# Copyright 2022 Google LLC
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should now be updated to 2023



# Keywords from user.
keyword_text_exact_1 = "example of exact match"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As module-level variables, these should be capitalized with leading underscores, for example:

_KEYWORD_TEXT_EXACT_1 = ...
_KEYWORD_TEXT_PHRASE_1 = ...
_KEYWORD_TEXT_BROAD_1 = ...

Feel free to reference the Smart Campaign example.

# Geo targeting from user.
location_1 = "Buenos aires"
location_2 = "San Isidro"
location_3 = "Mar del Plata"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above for these variables, capitalize with leading underscore.


# A list of country codes can be referenced here:
# https://developers.google.com/google-ads/api/reference/data/geotargets
COUNTRY_CODE = "AR"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two above variables should have leading underscores.

business_profile_location: the ID of a Business Profile location.
business_name: the name of a Business Profile.
"""
# [START Step 1 -- Create campaign and budget]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The [START xyz] notation is used to port specific sections of the example to our docs, so there's no need to include them here since this example isn't accompanied by a guide.

So this comment can just be:

# Step 1 -- Create campaign and budget

campaign_budget.amount_micros = 500000

# Add budget.
try:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you wrap the call to main in a try/catch at the bottom of the file then you don't need to handle any exceptions here or any where else in the file.

campaign_id = campaign_response.results[0].resource_name.split("/")[-1]
except GoogleAdsException as ex:
handle_googleads_exception(ex)
# [END Step 1 -- Create campaign and budget]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned earlier, you can remove the comment formatted that looks like:

  • [START xyz]
  • [END xyz]

Just leave the xyz part.

6 steps to create a Responsive Search Ad (RSA).
'''

def main(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you break this method into smaller methods where each is responsible for creating a single resource? Specifically the body in main should look something like:

def main(...):
    _create_campaign_budget(...)
    _create_campaign(...)
    _create_ad_group(...)

The smart campaign example does a good job of this in order to make the chunks of code more discernable for the reader.

@fblascogarma
Copy link
Contributor Author

Hi Ben, thank you for all your great recommendations. I have followed all of them and commit the changes.

Please review and let me know what you think.

Thank you!

Copy link
Contributor

@bobhancockg bobhancockg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please only use an initial underbar when it conforms with PEP8.

_single_leading_underscore: weak “internal use” indicator. E.g. from M import * does not import objects whose names start with an underscore.

"""
# Step 1.1 -- Create budget.
# Create a budget, which can be shared by multiple campaigns.
campaign_budget = _create_campaign_budget(client, customer_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above. Why is the initial underbar used?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my response above - it's because I asked for them to be changed. I remember now that we stopped using this pattern so agree let's remove the leading underscore from all the method names in this example.

@fblascogarma
Copy link
Contributor Author

Hi Ben, I removed the leading underscores in method names as requested.


Returns:
A responsive search ad with all settings required to run campaign.
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above lines (75-83) should be indented by 4 spaces.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TY!

# If the account does not meet the requirements, set below variable to False.
_ADD_IMAGE_EXTENSION = True

"""Support function"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not necessary to have this comment here, the PyDocs in each function are sufficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TY!



def create_ad_text_asset(client, text, pinned_field=None):
"""Create an AdTextAsset."""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PyDoc needs Args and Returns sections.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TY!

return ad_text_asset


"""6 steps to create a Responsive Search Ad (RSA)."""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to have this either.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TY!

# To add image extensions, the account has to follow these requirements:
# https://support.google.com/google-ads/answer/9566341
# If the account does not meet the requirements, set below variable to False.
_ADD_IMAGE_EXTENSION = True
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be converted into a CLI input (like this) since it can be toggled. These module-level variables should be used for values that are static.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TY!

# Create the campaign criterion for location targeting.
campaign_criterion_operation = client.get_type("CampaignCriterionOperation")
campaign_criterion = campaign_criterion_operation.create
campaign_criterion.campaign = campaign_service.campaign_path(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once you update the method to accept a campaign resource name you won't need to do this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TY!

for result in campaign_criterion_response.results:
print(f'Added campaign criterion "{result.resource_name}".')

return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No explicit return needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TY!

# Step 6.1 - Add Image Asset.

# Download image from URL.
url = "https://img.cppng.com/download/2020-06/66912-logo-now-google-plus-search-free-transparent-image-hd.png"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have images hosted specifically for this purpose, for example: https://gaagl.page.link/bjYi

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TY!

for row in mutate_asset_response.results:
print(f"\tResource name: {row.resource_name}")

image_asset_id = mutate_asset_response.results[0].resource_name.split("/")[-1]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to split out the ID here, you can just reuse the resource name as-is on line 507.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TY!

"Created a campaign extension setting with resource name: "
f"'{campaign_extension_response.results[0].resource_name}'"
)
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No explicit return.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TY!

Copy link
Contributor

@BenRKarl BenRKarl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one small change then we're good to go.

)
ad_resource_name = result.resource_name.split("/")[-1]

return ad_resource_name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this value isn't used by the calling code, so no need to even return it at all, just remove everything below the print statement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TY!

# To add image extensions, the account has to follow these requirements:
# https://support.google.com/google-ads/answer/9566341
# If the account meets the requirements, set below variable to True.
if omit_image_extensions:
Copy link
Member

@jradcliff jradcliff Mar 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be if not omit_image_extensions, correct?

On that note, could we make this include_image_extensions and have it default to True instead? That would make the logic more readable and avoid a double negative for the "do something" case. Then the code here would be:

if include_image_extensions:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right! Let's change it to include_image_extensions, but I would still have it as False as a default because not all accounts can create them. Therefore, we avoid developers getting errors.

# The bidding strategy for Maximize Clicks is TargetSpend.
# The target_spend_micros is deprecated so don't put any value.
# See other bidding strategies you can select in the link below.
# https://developers.google.com/google-ads/api/reference/rpc/v11/Campaign#campaign_bidding_strategy
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change v11 to latest so this isn't version dependent.



def add_images(client, customer_id, campaign_resource_name):
# Step 6.1 - Add Image Asset.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these numbered steps correspond to upcoming changes to documentation? I noticed they're only present in this method.

Comment on lines +438 to +447
asset.image_asset.file_size = len(image_content)

# MIME type of the image (IMAGE_JPEG, IMAGE_PNG, etc.).
# See more types on the link below.
# https://developers.google.com/google-ads/api/reference/rpc/v11/MimeTypeEnum.MimeType
asset.image_asset.mime_type = client.enums.MimeTypeEnum.IMAGE_PNG
# Use your favorite image library to determine dimensions
asset.image_asset.full_size.height_pixels = 1200
asset.image_asset.full_size.width_pixels = 1200
asset.image_asset.full_size.url = url
Copy link
Member

@jradcliff jradcliff Mar 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is setting file_size and full_size necessary? We don't set any of those attributes in https://developers.google.com/google-ads/api/samples/upload-image#python, but we do in https://developers.google.com/google-ads/api/samples/upload-image-asset#python.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tested by taking them out, and I didn't get any errors. Therefore, we could comment them out or remove them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants