Question:
I am having trouble with submitting batch requests for the Facebook Ads API, and I was wondering if anyone could provide insight on the below error.
I am attempting to take a list of artists, just 50 in this simplified example, and then submit a TargetingSearch request for those artists. However, I'm having trouble getting the request to pass through correctly to Facebook. You could imagine a case where I'm passing thousands of artists into here.
I've been using these two resources for batch requesting ad/ad-set insights in the facebook-ads-api for Python as a reference: https://github.com/facebook/facebook-python-ads-sdk/issues/116 https://github.com/linpingta/facebook-related/blob/master/facebook-ads-sdk-example/insight_related.py
My code:
import time
list_of_artists = ['Adele','Alessia Cara','Ariana Grande','Big Sean','Blake Shelton','Brantley Gilbert','Brett Young','Bruno Mars','Calvin Harris','Camila Cabello','Carrie Underwood','Chris Brown','Chris Stapleton','Chuck Berry','Cole Swindell','Dierks Bentley','DJ Khaled','Ed Sheeran','Eminem','Eric Church','Future','G-Eazy','Gucci Mane','James Arthur','Jason Aldean','John Legend','Jon Pardi','Josh Turner','Julia Michaels','Justin Bieber','Justin Timberlake','Katy Perry','Kehlani','Keith Urban','Kelsea Ballerini','Kendrick Lamar','Kenny Chesney','Khalid','Kodak Black','Kygo','Kyle Harvey','Lady Gaga','Lil Yachty','Lorde','Luis Fonsi','Luke Bryan','Luke Combs','Machine Gun Kelly (Rapper)']
def success_callback(response):
batch_body_responses.append(response.body())
def error_callback(response):
# Error handling here
pass
def get_id_list(art_search_list):
batches = []
batch_body_responses = []
your_app_id = '<appid>'
your_app_secret = '<appsecret>'
your_access_token = '<token>'
api = FacebookAdsApi.init(your_app_id, your_app_secret, your_access_token)
batch_limit = 25
for batch in generate_batches(art_search_list, batch_limit):
next_batch = api.new_batch()
for art in batch:
requests = TargetingSearch.search(params = {'q': art,'type': 'adinterest'})
for req in requests:
# adding a print to see what req looks like
print req
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
get_id_list(list_of_artists)
This results in the below error:
Note: the TargetingSearch is from the print req above.
<TargetingSearch> {
"audience_size": 30176300,
"id": "6003173089178",
"name": "Adele",
"path": [
"Interests",
"Additional Interests",
"Adele"
],
"topic": "People"
}
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-299-67aa05ef2228> in <module>()
33 print batch_body_responses
34
---> 35 get_id_list(list_of_artists)
36
37 # # #################
<ipython-input-299-67aa05ef2228> in get_id_list(art_search_list)
24 # adding a print to see what req looks like
25 print req
---> 26 next_batch.add_request(req, success_callback, error_callback)
27 batches.append(next_batch)
28
//anaconda/lib/python2.7/site-packages/facebookads/api.pyc in add_request(self, request, success, failure)
445 A dictionary describing the call.
446 """
--> 447 updated_params = copy.deepcopy(request._params)
448 if request._fields:
449 updated_params['fields'] = ','.join(request._fields)
AttributeError: 'TargetingSearch' object has no attribute '_params'
If I could correctly pass the batches to Facebook, I would expect an answer that gave me the TargetingSearch results for each artist. Here's an example for Adele, but you could imagine this being replicated for each:
[<TargetingSearch> {
"audience_size": 30176300,
"id": "6003173089178",
"name": "Adele",
"path": [
"Interests",
"Additional Interests",
"Adele"
],
"topic": "People"
}, <TargetingSearch> {
"audience_size": 20449710,
"id": "6003701797690",
"name": "21 (Adele album)",
"path": [
"Interests",
"Additional Interests",
"21 (Adele album)"
],
"topic": "News and entertainment"
}, <TargetingSearch> {
"audience_size": 256080,
"disambiguation_category": "Song",
"id": "6005916496872",
"name": "Someone like You (Adele song)",
"path": [
"Interests",
"Additional Interests",
"Someone like You (Adele song)"
],
"topic": "News and entertainment"
}, <TargetingSearch> {
"audience_size": 130230,
"disambiguation_category": "Home",
"id": "6002994499323",
"name": "Adele Live",
"path": [
"Interests",
"Additional Interests",
"Adele Live"
]
}, <TargetingSearch> {
"audience_size": 31410,
"disambiguation_category": "Song",
"id": "6004484416351",
"name": "Rumour Has It (Adele song)",
"path": [
"Interests",
"Additional Interests",
"Rumour Has It (Adele song)"
],
"topic": "News and entertainment"
}, <TargetingSearch> {
"audience_size": 4560,
"disambiguation_category": "Public Figure",
"id": "6003446313480",
"name": "Adele Parks",
"path": [
"Interests",
"Additional Interests",
"Adele Parks"
],
"topic": "People"
}, <TargetingSearch> {
"audience_size": 2290,
"id": "6002970343768",
"name": "Adele ring",
"path": [
"Interests",
"Additional Interests",
"Adele ring"
],
"topic": "Education"
}, <TargetingSearch> {
"audience_size": 990,
"disambiguation_category": "Musician/Band",
"id": "6003213600533",
"name": "Adele - Official Website",
"path": [
"Interests",
"Additional Interests",
"Adele - Official Website"
]
}]
I think I'm having trouble understanding how to pass around / customize the requests and generate them in a batch that can be executed.
-Thanks, Jordan
My Solution (Perhaps Room for Improvement)
I ended up figuring our a solution to my question, it's most likely not the best one but it works for now. I've left the question and incorrect code that I initially submitted below under its own header just in case anyone else learning about batch requests with the Facebook API and would find it helpful to see how I fixed this.
My initials concerns were right, I was essentially trying to submit TargetingSearch calls as a request, but in actuality they were executing before ever being passed as batch requests.
What I needed to do was:
Use FacebookRequest to create a "GET" request using the "/targetingsearch" endpoint and then append the parameters for the query using .add_params which change depending on the item in the batch.
Add in some error handling to the callback function. Some of the artists searched might not actually return anything for a result, if you tried to pull the ID and Name using indexing, you'd get an error.
I elected to import pandas and turn the results into a dataframe just so that it was easier to read.
Tip: Intentionally submitting incorrect calls to FB helped me troubleshoot because the error messaging that gets spit back shows you the actual request being made.
Code:
Result: