Here's one of the weirdest issue I have ever experienced with an API. Let's see, so I am using the Facebook Business API, and it works fine for most requests I do, however there are some accounts that behave very strange.
Let's see, if I call this:
accounts_general_fields = ['account_id', 'business_name', 'account_status', 'age', 'amount_spent','balance','currency']
print(me.get_ad_accounts(fields=accounts_general_fields))
this works fine, there is not issue, however when I want to iterative over it, for example
accounts= list(me.get_ad_accounts(fields=accounts_general_fields))
accounts= me.get_ad_accounts(fields=accounts_general_fields)
accounts_fixed = [account.api_get(fields=accounts_general_fields) for account in accounts]
accounts= me.get_ad_accounts(fields=accounts_general_fields)
accounts_fixed = [account.export_all_data() for account in accounts]
or
accounts= me.get_ad_accounts(fields=accounts_general_fields)
accounts_fixed = [account for account in accounts]
it gets this:
facebook_business.exceptions.FacebookRequestError:
Message: Call was not successful
Method: GET
Path: https://graph.facebook.com/v20.0/me/adaccounts
Params: {'fields': 'account_id,business_name,account_status,age,amount_spent,balance,currency', 'summary': 'true', 'after': 'MjM4NDM4NDA2MTg4NjAxMjkZD'}
Status: 400
Response:
{
"error": {
"message": "(#80004) There have been too many calls to this ad-account. Wait a bit and try again. For more info, please refer to https://developers.facebook.com/docs/graph-api/overview/rate-limiting#ads-management.",
"type": "OAuthException",
"code": 80004,
"error_subcode": 2446079,
"fbtrace_id": "ArA51rxNPTHAl7CrHVCaEWG"
}
}
This behavior happens with other endpoints, for example:
AdAccount(ad_account_id).get_campaigns(fields=fields)
and
AdAccount(ad_account_id).get_campaigns(fields=fields)
but just for specific ad accounts, like 3 or 4 accounts of 300 accounts. I don't know what could be happening. Here is my implementation for those endpoints:
def fetch_adsets_for_account(ad_account_id, fields):
try:
return list(AdAccount(ad_account_id).get_ad_sets(fields=fields))
except Exception as e:
print(f"Failed to fetch ad sets for ad account {ad_account_id}: {e}")
return []
def fetch_adsets_data(ad_account_ids, fields):
all_data = []
# Use ThreadPoolExecutor to fetch data in parallel
with concurrent.futures.ThreadPoolExecutor(max_workers=30) as executor:
# Create a list of futures
futures = {executor.submit(fetch_adsets_for_account, ad_account_id, fields): ad_account_id for ad_account_id in ad_account_ids}
# As each future completes, append the result to all_data
for future in concurrent.futures.as_completed(futures):
try:
data = future.result()
all_data.extend(data)
except Exception as e:
ad_account_id = futures[future]
print(f"An error occurred for ad account {ad_account_id}: {e}")
# Convert the collected data to a DataFrame
df = pd.DataFrame(all_data)
return df
# Example usage:
ad_account_ids = df_accounts["id"].tolist()[:]
fields = ['name', 'status', 'start_time', 'lifetime_budget']
start = time.time()
df_individual_adsets = fetch_adsets_data(ad_account_ids, fields)
df_individual_adsets["date"] = today_data
end = time.time()
print(end - start)
Here's one example of the problem for this:
Failed to fetch ad sets for ad account act_400136354038554:
Message: Call was not successful
Method: GET
Path: https://graph.facebook.com/v20.0/act_400136354038554/adsets
Params: {'fields': 'name,status,start_time,lifetime_budget', 'summary': 'true', 'after': 'QVFIUmM2a3VXdG5XRG43OFd3ZAVdLNlV5d1BaR3NlWFlyTk9zQW5yaElIYWZAieVF0b3pFMUphV0tIZAmR4VEE2S3J0LTIZD'}
Status: 400
Response:
{
"error": {
"message": "User request limit reached",
"type": "OAuthException",
"is_transient": false,
"code": 17,
"error_subcode": 2446079,
"error_user_title": "Ad Account Has Too Many API Calls",
"error_user_msg": "There have been too many calls from this ad-account. Please wait a bit and try again.",
"fbtrace_id": "A-LW6ciS_vyN_vkhK5CD0tW"
}
}
Facebook Business SDK for Python sucks, I solved this issue with this:
def fetch_adsets_for_account(ad_account_id, fields):
try:
data = AdAccount(ad_account_id).get_ad_sets(fields=fields, params={"limit": 2000})
data_final = [data.export_all_data() for data in data]
return data_final
except Exception as e:
print(f"Failed to fetch ad sets for ad account {ad_account_id}: {e}")
return []
Essentially you only need to define a high limit and it will work as expected!