skip to Main Content

I’m trying to build an API tool for creating 100+ campaigns at a time, but so far I keep running into timeout errors. I have a feeling it’s because I’m not doing this as a batch/async request, but I can’t seem to find straightforward instructions specifically for batch creating campaigns in Python. Any help would be GREATLY appreciated!

I have all the campaign details prepped and ready to go in a Google sheet, which my script then reads (using pygsheets) and attempts to create the campaigns. Here’s what it looks like so far:

from facebookads.adobjects.campaign import Campaign
from facebookads.adobjects.adaccount import AdAccount
from facebookads.api import FacebookAdsApi
from facebookads.exceptions import FacebookRequestError
import time
import pygsheets

FacebookAdsApi.init(access_token=xxx)
gc = pygsheets.authorize(service_file='xxx/client_secret.json')

sheet = gc.open('Campaign Prep')
tab1 = sheet.worksheet_by_title('Input')
tab2 = sheet.worksheet_by_title('Output')
# gets range size, offsetting it by 1 to account for the range starting on row 2
row_range = len(tab1.get_values('A1', 'A', returnas='matrix', majdim='ROWS', include_empty=False))+1
# finds first empty row in the output sheet
start_row = len(tab2.get_values('A1', 'A', returnas='matrix', majdim='ROWS', include_empty=False))

def create_campaigns(row):
    campaign = Campaign(parent_id=row[6])
    campaign.update({
        Campaign.Field.name: row[7],
        Campaign.Field.objective: row[9],
        Campaign.Field.buying_type: row[10],
        })
    c = campaign.remote_create(params={'status': Campaign.Status.active})
    camp_name = c['name']
    camp_id = 'cg:'+c['id']
    return camp_name, camp_id

r = start_row
# there's a header so I have the range starting at 2
for x in range(2, int(row_range)):
        r += 1
        row = tab1.get_row(x)
        camp_name, camp_id = create_campaigns(row)
        # pastes the generated campaign ID, campaign name and account id back into the sheet
        tab2.update_cells('A'+str(r)+':C'+str(r).format(r),[[camp_id, camp_name, row[6].rsplit('_',1)[1]]])

I’ve tried putting this in a try loop and if it runs into a FacebookRequestError have it do time.sleep(5) then keep trying, but I’m still running into timeout errors every 5 – 10 rows it loops through. When it doesn’t timeout it does work, I guess I just need to figure out a way to make this handle big batches of campaigns more efficiently.

Any thoughts? I’m new to the Facebook API and I’m still a relative newb at Python, but I find this stuff so much fun! If anyone has any advice for how this script could be better (as well as general Python advice), I’d love to hear it! 🙂

2

Answers


  1. Can you post the actual error message?

    It sounds like what you are describing is that you hit the rate limits after making a certain amount of calls. If that is so, time.sleep(5) won’t be enough. The rate score decays over time and will be reset after 5 minutes https://developers.facebook.com/docs/marketing-api/api-rate-limiting. In that case I would suggest making a sleep between each call instead. However a better option would be to upgrade your API status. If you hit the rate limits this fast I assume you are on Developer level. Try upgrading first to Basic and then Standard and you should not have these problems. https://developers.facebook.com/docs/marketing-api/access

    Also, as you mention, utilizing Facebook’s batch request API could be a good idea. https://developers.facebook.com/docs/marketing-api/asyncrequests/v2.11

    Here is a thread with examples of the Batch API working with the Python SDK: https://github.com/facebook/facebook-python-ads-sdk/issues/116

    Login or Signup to reply.
  2. I paste the code snippet (copied from the last link that @reaktard pasted), credit to github user @williardx

    it helped me a lot in my development.

    # ----------------------------------------------------------------------------
    # Helper functions
    
    def generate_batches(iterable, batch_size_limit):
        # This function can be found in examples/batch_utils.py
        batch = []
    
        for item in iterable:
            if len(batch) == batch_size_limit:
                yield batch
                batch = []
            batch.append(item)
    
        if len(batch):
            yield batch
    
    def success_callback(response):
        batch_body_responses.append(response.body())
    
    def error_callback(response):
        # Error handling here
        pass
    
    # ----------------------------------------------------------------------------
    
    batches = []
    batch_body_responses = []
    api = FacebookAdsApi.init(your_app_id, your_app_secret, your_access_token)
    
    for ad_set_list in generate_batches(ad_sets, batch_limit):
        next_batch = api.new_batch()
        requests = [ad_set.get_insights(pending=True) for ad_set in ad_set_list]
    
        for req in requests:
            next_batch.add_request(req, success_callback, error_callback)
        batches.append(next_batch)
    
    for batch_request in batches:
        batch_request.execute()
        time.sleep(5)
    
    print batch_body_responses
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search