Beispiel #1
0
def get_ad_set_data(ad_account: adaccount.AdAccount) -> {}:
    """Retrieves the ad set data of the ad account as a dictionary

    Args:
        ad_account: An ad account for which to retrieve the ad set data

    Returns:
        A dictionary with {ad_set_id: {'name': 1,
                                       'campaign_id': 2,
                                       'attributes': {}}} format

    """
    logging.info('get ad set data for account {}'.format(
        ad_account['account_id']))
    ad_sets = ad_account.get_ad_sets(
        fields=['id', 'name', 'campaign_id', 'adlabels'],
        params={
            'limit': 1000,
            'status': ['ACTIVE', 'PAUSED', 'ARCHIVED']
        })
    result = {}

    for ad_set in ad_sets:
        result[ad_set['id']] = {
            'name': ad_set['name'],
            'campaign_id': ad_set['campaign_id'],
            'attributes': parse_labels(ad_set.get('adlabels', []))
        }
    return result
def view_ad(request):
    FacebookAdsApi.init(access_token=access_token,
                        app_id=app_id,
                        app_secret=app_secret)
    my_account = AdAccount('act_' + user_id)
    adsets = my_account.get_ad_sets()
    adset_id = []
    for i in range(len(adsets)):
        adset_id.append(adsets[i]["id"])

    for adset in adset_id:
        ad_set = AdSet(adset)
        fields = [
            Ad.Field.name,
            Ad.Field.id,
        ]
        ad_iter = ad_set.get_ads(fields=fields)
    ad_data = []
    for ad in ad_iter:
        result = {}
        result["id"] = ad[Ad.Field.id]
        result["name"] = ad[Ad.Field.name]
        ad_data.append(result)
    context = {'ads': ad_data}

    return render(request, 'fbapp/view_ad.html', context)
def view_adset(request):
    FacebookAdsApi.init(access_token=access_token,
                        app_id=app_id,
                        app_secret=app_secret)

    my_account = AdAccount('act_' + user_id)

    adsets = my_account.get_ad_sets()
    adset_id = []
    for i in range(len(adsets)):
        adset_id.append(adsets[i]["id"])

    adset_data = []
    for id in adset_id:
        adset = AdSet(fbid=id)
        fields = [
            AdSet.Field.name,
            AdSet.Field.effective_status,
            AdSet.Field.campaign_id,
            AdSet.Field.status,
        ]
        adset.remote_read(fields=fields)

        result = {}
        result["id"] = id
        result["name"] = adset[AdSet.Field.name]
        result["campid"] = adset[AdSet.Field.campaign_id]
        result["status"] = adset[AdSet.Field.status]
        result["data_1"] = "ACTIVE"
        result["data_2"] = "PAUSED"
        adset_data.append(result)

    context = {'adsets': adset_data}

    return render(request, 'fbapp/view_adset.html', context)
Beispiel #4
0
def get_request(account_id, table, params, fields):
    """account_id: unique id for ad account in format act_<ID>
    table: The table object found in the models module
    params: dictionary of parameters for request
    fields: list of fields for request
    --> returns requested data from Facebook Marketing API
    """
    my_account = AdAccount(account_id)
    if table == 'accounts':
        cursor = my_account.api_get(params=params, fields=fields)
        return dict(cursor)
    if table == 'campaigns':
        cursor = my_account.get_campaigns(params=params, fields=fields)
        request = [campaign for campaign in cursor]
        return request
    if table == 'adsets':
        request = my_account.get_ad_sets(params=params, fields=fields)
        return request
    if table == 'ads_insights':
        cursor = my_account.get_insights_async(params=params, fields=fields)
        cursor.api_get()
        while cursor[AdReportRun.Field.async_status] != "Job Completed":
            time.sleep(1)
            cursor.api_get()
            time.sleep(1)
        request = cursor.get_result(params={"limit": 1000})
        return request
    if table == 'ads_insights_age_and_gender':
        cursor = my_account.get_insights_async(params=params, fields=fields)
        cursor.api_get()
        while cursor[AdReportRun.Field.async_status] != "Job Completed":
            time.sleep(1)
            cursor.api_get()
            time.sleep(1)
        request = cursor.get_result(params={"limit": 1000})
        return request
    if table == 'ads_insights_region':
        cursor = my_account.get_insights_async(params=params, fields=fields)
        cursor.api_get()
        while cursor[AdReportRun.Field.async_status] != "Job Completed":
            time.sleep(1)
            cursor.api_get()
            time.sleep(1)
        request = cursor.get_result(params={"limit": 1000})
        return request
Beispiel #5
0
def getAds(my_app_id, my_app_secret, my_access_token, account_id):
    FacebookAdsApi.init(my_app_id, my_app_secret, my_access_token)
    account = AdAccount(account_id)
    ad_set = account.get_ad_sets()
    print(ad_set)
Beispiel #6
0
from facebook_business.adobjects.adset import AdSet


my_app_id = cfg.fb_app_id
my_app_secret = cfg.fb_app_secret
my_access_token = cfg.fb_token



auth_url = f"https://graph.facebook.com/oauth/access_token?client_id={cfg.fb_app_id}&client_secret={my_app_secret}&redirect_uri={cfg.redirect}&grant_type=client_credentials"
logger.info(f'auth url: {auth_url}')


FacebookAdsApi.init(my_app_id, my_app_secret, my_access_token)

id = 'act_207528810141959'
account = AdAccount(id)
adsets = account.get_ad_sets(fields=[AdSet.Field.name])

for adset in adsets:
    print(adset[AdSet.Field.name])

# my_accounts = list(me.get_ad_accounts())
# print(my_accounts)

# campaigns = my_account
# print(campaigns)



Beispiel #7
0
    def get_ad_sets(self, account_id, include_archived, limit):
        """
        Retrieves and displays a list of ad sets of a given account,
        and analyze how likely a similar ad for Instagram can be created.

        Params:

        * `account_id` is your Facebook Ad Account id.
        * `include_archived` specifies whether archived ad sets should be
          analyzed.
        * `limit` is how many ad sets to analyze. This script will analyze the
          first `limit` ad sets as in the response, not including those which
          use Instagram placement already. The more this limit is, the longer
          it takes to run. If you run the script directly and are willing
          to wait for a while, you can drop the lines of code around it.

        For more information see the [Instagram Ads document](
        https://developers.facebook.com/docs/marketing-api/guides/instagramads/)
        """
        locale.setlocale(locale.LC_ALL, '')
        if include_archived:
            params = {
                'limit':
                limit,
                AdSet.Field.configured_status: [
                    'PENDING', 'ACTIVE', 'PAUSED', 'PENDING_REVIEW',
                    'DISAPPROVED', 'PREAPPROVED', 'PENDING_BILLING_INFO',
                    'CAMPAIGN_PAUSED', 'CAMPAIGN_GROUP_PAUSED', 'ARCHIVED'
                ],
            }
        else:
            params = {'limit': limit}
        account = AdAccount(account_id)
        ad_sets = account.get_ad_sets(fields=[
            AdSet.Field.id,
            AdSet.Field.campaign_id,
            AdSet.Field.name,
            AdSet.Field.configured_status,
            AdSet.Field.targeting,
        ],
                                      params=params)
        cache = {}
        count = 0
        results = []
        for ad_set in ad_sets:
            if count >= limit:
                break
            count += 1

            result = {}
            result['id'] = ad_set['id']
            result['name'] = ad_set['name']
            logger.error(ad_set)

            # Get targeting from ad set
            targeting = ad_set.get(AdSet.Field.targeting, None)
            logger.error(targeting)
            if targeting is not None:
                publisher_platforms = targeting.get('publisher_platforms',
                                                    None)
                pp_str = ''
                if publisher_platforms is None:
                    result['publisher_platforms'] = '<li>DEFAULT</li>'
                else:
                    for pp in publisher_platforms:
                        pp_str += ('<li>' + self.translate_placement_publisher(
                            str(pp)) + '</li>')
                    result['publisher_platforms'] = pp_str

                params = {
                    'currency': 'USD',
                    'targeting_spec': targeting,
                    'optimize_for': AdSet.OptimizationGoal.impressions,
                }

                if publisher_platforms is not None and "instagram" in \
                        publisher_platforms:
                    count -= 1
                    continue

                reach_fb = account.get_reach_estimate(params=params)[0].get(
                    'users', 0)

                targeting['publisher_platforms'] = ["instagram"]
                targeting['facebook_positions'] = None
                params = {
                    'currency': 'USD',
                    'targeting_spec': targeting,
                    'optimize_for': AdSet.OptimizationGoal.impressions,
                }
                reach_ig = account.get_reach_estimate(params=params)[0].get(
                    'users', 0)

                self.add_check_result(result,
                                      self.check_audience(reach_fb, reach_ig))
                result["audience"] = reach_ig * 100 / reach_fb
                result["ig_audience"] = locale.format("%d",
                                                      reach_ig,
                                                      grouping=True)
            # Get objective and status from Campaign
            campaign_id = ad_set[AdSet.Field.campaign_id]
            campaign = self.get_ad_campaign(cache, campaign_id)
            result["c_objective"] = \
                campaign[Campaign.Field.objective].replace("_", " ")
            result["c_status"] = campaign[Campaign.Field.configured_status]
            check = self.check_objective(result["c_objective"])
            if check['eligibility'] == 5:
                result['objective_supported'] = 1
            elif check['eligibility'] == 1:
                result['objective_supported'] = 0
            else:
                result['objective_supported'] = 2

            self.add_check_result(result, check)

            # Get creative and check the media
            if campaign[Campaign.Field.objective] == 'PRODUCT_CATALOG_SALES':
                result['preview_url'] = \
                    'Images from product catalog are not supported.'
                results.append(result)
                result['creative_ready'] = False
                continue

            creatives = ad_set.get_ad_creatives([
                AdCreative.Field.object_story_id,
            ])
            result['creative_ready'] = False
            if not creatives:
                comment = 'No creative found in this ad set.'
                self.add_check_result(result, {
                    "eligibility": 3,
                })
                result['preview_url'] = comment
                results.append(result)
                continue
            creative = creatives[0]
            story_id = creative.get(AdCreative.Field.object_story_id, 0)
            if story_id == 0:
                comment = 'No post fround in the first creative of this ad set.'
                self.add_check_result(result, {
                    "eligibility": 3,
                })
                result['preview_url'] = comment
                results.append(result)
                continue

            # Check whether the creative's post is IG ready
            try:
                # This Graph API call is not a part of Ads API thus no SDK
                post = FacebookAdsApi.get_default_api().call(
                    'GET',
                    (story_id, ),
                    params={
                        'fields': 'is_instagram_eligible,child_attachments'
                    },
                )
                post_ig_eligible = post.json()['is_instagram_eligible']
            except FacebookRequestError:
                post_ig_eligible = False
            result['creative_ready'] = post_ig_eligible
            if post_ig_eligible:
                self.add_check_result(result, {
                    "eligibility": 5,
                })

                # Generate preview
                # As we do not know which IG account you will use,
                # just use a hardcoded one for preview.
                jasper_ig_account = "1023317097692584"
                ad_format = AdPreview.AdFormat.instagram_standard
                creative_spec = {
                    AdCreative.Field.instagram_actor_id: jasper_ig_account,
                    AdCreative.Field.object_story_id: story_id,
                }
                params = {
                    'creative': creative_spec,
                    'ad_format': ad_format,
                }
                preview = account.get_generate_previews(params=params)
                result['preview_url'] = preview[0].get_html() \
                    .replace('width="320"', 'width="340"', 1)
            else:
                comment = 'The creative needs to be modified for Instagram.'
                self.add_check_result(result, {
                    "eligibility": 3,
                })
                result['preview_url'] = comment
            results.append(result)
        return list(
            sorted(results,
                   key=lambda result: result['eligibility'],
                   reverse=True))
    def retrieve_eligible_adsets_for_an(
        self,
        accountid,
        includepaused=False,
    ):
        """
        This method returns all eligible ad sets that can have audience
        networked turned on for a given ad account id.

        Args:
            accountid: The ad account id (should be of the form act_<act_id>)
                for which you are running this exercise.
            inlcudepaused: Boolen parameter to make your method consider ad
                sets with paused states (PAUSED & CAMPAIGN_PAUSED). Checks
                only ACTIVE by default.

        Returns:
            List of ad set objects (if found satisfying the conditions) or
            an empty list.

        """
        # use accountid to retrieve all active adsets
        account = AdAccount(accountid)
        adsetfields = [
            AdSet.Field.id,
            AdSet.Field.name,
            AdSet.Field.campaign_id,
            AdSet.Field.targeting,
            AdSet.Field.effective_status,
        ]
        adsets = list(account.get_ad_sets(fields=adsetfields))

        # Filter ad sets received by desired status and placement types.
        # Further filter by campaign objectives listed in the criteria below.
        #
        # Ref: https://developers.facebook.com/docs/
        #               marketing-api/audience-network/v2.5

        desired_campaign_status = set(['ACTIVE'])

        # mostly useful in testing when you don't have active campaigns
        if includepaused is True:
            desired_campaign_status.update({'PAUSED', 'CAMPAIGN_PAUSED'})

        desired_campaign_objectives = set([
            'MOBILE_APP_INSTALLS',
            'MOBILE_APP_ENGAGEMENT',
            'LINK_CLICKS',
            'CONVERSIONS',
            'PRODUCT_CATALOG_SALES',
        ])

        # Hold the result set
        eligible_adsets = []

        for adset in adsets:
            if adset[AdSet.Field.effective_status] in desired_campaign_status:
                """
                'devide_platforms', 'publisher_platforms' and
                'facebook_positions' could be absent for the default of 'ALL'
                """
                device_platforms = None
                if Targeting.Field.device_platforms in \
                        adset[AdSet.Field.targeting]:
                    device_platforms = set(adset[AdSet.Field.targeting][
                        Targeting.Field.device_platforms])

                publisher_platforms = None
                if Targeting.Field.publisher_platforms in \
                        adset[AdSet.Field.targeting]:
                    publisher_platforms = set(adset[AdSet.Field.targeting][
                        Targeting.Field.publisher_platforms])

                facebook_positions = None
                if Targeting.Field.facebook_positions in \
                        adset[AdSet.Field.targeting]:
                    facebook_positions = set(adset[AdSet.Field.targeting][
                        Targeting.Field.facebook_positions])

                if ((facebook_positions is None
                     or 'feed' in facebook_positions)
                        and (device_platforms is None
                             or 'mobile' in device_platforms)):

                    if (publisher_platforms is None
                            or 'audience_network' in publisher_platforms):
                        # audience network already enabled, so just pass
                        continue
                    else:
                        campaign = Campaign(adset[AdSet.Field.campaign_id])
                        campaignfields = [
                            Campaign.Field.id,
                            Campaign.Field.name,
                            Campaign.Field.effective_status,
                            Campaign.Field.objective,
                        ]
                        campaign = campaign.remote_read(fields=campaignfields)
                        if (campaign[Campaign.Field.objective]
                                in desired_campaign_objectives):
                            eligible_adsets.append(adset)

        return eligible_adsets
Beispiel #9
0
class LibFacebook:
    def __init__(self, app_id, app_secret, access_token, ad_account_id):
        FacebookAdsApi.init(app_id, app_secret, access_token)
        self.account = AdAccount(ad_account_id)

    def create_ad_tree(self):
        # Campaign fields
        fields = ["id",
                  "account_id",
                  "adlabels",
                  "bid_strategy",
                  "boosted_object_id",
                  "brand_lift_studies",
                  "budget_rebalance_flag",
                  "budget_remaining",
                  "buying_type",
                  "can_create_brand_lift_study",
                  "can_use_spend_cap",
                  "configured_status",
                  "created_time",
                  "daily_budget",
                  "effective_status",
                  "issues_info",
                  "lifetime_budget",
                  "name",
                  "objective",
                  "recommendations",
                  "source_campaign",
                  "source_campaign_id",
                  "spend_cap",
                  "start_time",
                  "status",
                  "stop_time",
                  "updated_time"]

        # List of all campaigns
        campaigns = self.account.get_campaigns(fields=fields)

        # Ad set fields
        fields = ["id",
                  "account_id",
                  "adlabels",
                  "adset_schedule",
                  "attribution_spec",
                  "bid_amount",
                  "bid_info",
                  "bid_strategy",
                  "billing_event",
                  "budget_remaining",
                  "campaign",
                  "campaign_id",
                  "configured_status",
                  "created_time",
                  "creative_sequence",
                  "daily_budget",
                  "daily_min_spend_target",
                  "daily_spend_cap",
                  "destination_type",
                  "effective_status",
                  "end_time",
                  "frequency_control_specs",
                  "instagram_actor_id",
                  "is_dynamic_creative",
                  "issues_info",
                  "lifetime_budget",
                  "lifetime_imps",
                  "lifetime_min_spend_target",
                  "lifetime_spend_cap",
                  "name",
                  "optimization_goal",
                  "pacing_type",
                  "promoted_object",
                  "recommendations",
                  "recurring_budget_semantics",
                  "rf_prediction_id",
                  "source_adset",
                  "source_adset_id",
                  "start_time",
                  "status",
                  "targeting",
                  "time_based_ad_rotation_id_blocks",
                  "time_based_ad_rotation_intervals",
                  "updated_time",
                  "use_new_app_click"]

        # List of all ad sets
        ad_sets = self.account.get_ad_sets(fields=fields)

        # Ad fields
        fields = ["id",
                  "account_id",
                  "ad_review_feedback",
                  "adlabels",
                  "adset",
                  "adset_id",
                  "bid_amount",
                  "bid_info",
                  "bid_type",
                  "campaign",
                  "campaign_id",
                  "configured_status",
                  "conversion_specs",
                  "created_time",
                  "creative",
                  "effective_status",
                  "issues_info",
                  "last_updated_by_app_id",
                  "name",
                  "recommendations",
                  "source_ad",
                  "status",
                  "tracking_specs",
                  "updated_time"]

        # List of all ads
        ads = self.account.get_ads(fields=fields)

        ad_tree = []
        for i in campaigns:
            ad_structure_dict = {"campaign": i.export_all_data(),
                                 "adset_list": []}

            a = 0
            for j in ad_sets:
                if j["campaign_id"] == i["id"]:
                    ad_structure_dict["adset_list"].append({"ad_set": j.export_all_data(),
                                                            "ad_list": []})

                    for k in ads:
                        if k["adset_id"] == j["id"]:
                            ad_structure_dict["adset_list"][a]["ad_list"].append({"ad": k.export_all_data()})

                    a += 1

            ad_tree.append(ad_structure_dict)

        return ad_tree
Beispiel #10
0
class FbApi(object):
    def __init__(self, config_file=None):
        self.config_file = config_file
        self.df = pd.DataFrame()
        self.config = None
        self.account = None
        self.campaign = None
        self.app_id = None
        self.app_secret = None
        self.access_token = None
        self.act_id = None
        self.config_list = []
        self.date_lists = None
        self.field_lists = None
        self.adset_dict = None
        self.cam_dict = None
        self.ad_dict = None
        self.pixel = None
        if self.config_file:
            self.input_config(self.config_file)

    def input_config(self, config_file):
        logging.info('Loading Facebook config file: ' + str(config_file))
        self.config_file = os.path.join(config_path, config_file)
        self.load_config()
        self.check_config()
        FacebookAdsApi.init(self.app_id, self.app_secret, self.access_token)
        self.account = AdAccount(self.config['act_id'])

    def load_config(self):
        try:
            with open(self.config_file, 'r') as f:
                self.config = json.load(f)
        except IOError:
            logging.error(self.config_file + ' not found.  Aborting.')
            sys.exit(0)
        self.app_id = self.config['app_id']
        self.app_secret = self.config['app_secret']
        self.access_token = self.config['access_token']
        self.act_id = self.config['act_id']
        self.config_list = [
            self.app_id, self.app_secret, self.access_token, self.act_id
        ]

    def check_config(self):
        for item in self.config_list:
            if item == '':
                logging.warning(item + 'not in FB config file.  Aborting.')
                sys.exit(0)

    def set_id_name_dict(self, fb_object):
        if fb_object == Campaign:
            fields = ['id', 'name']
            self.cam_dict = list(self.account.get_campaigns(fields=fields))
        elif fb_object == AdSet:
            fields = ['id', 'name', 'campaign_id']
            self.adset_dict = list(self.account.get_ad_sets(fields=fields))
        elif fb_object == Ad:
            fields = ['id', 'name', 'campaign_id', 'adset_id']
            self.ad_dict = list(self.account.get_ads(fields=fields))

    def campaign_to_id(self, campaigns):
        if not self.cam_dict:
            self.set_id_name_dict(Campaign)
        cids = [x['id'] for x in self.cam_dict if x['name'] in campaigns]
        return cids

    def adset_to_id(self, adsets, cids):
        as_and_cam = list(itertools.product(adsets, cids))
        if not self.adset_dict:
            self.set_id_name_dict(AdSet)
        asids = [
            tuple([x['id'], x['campaign_id']]) for x in self.adset_dict
            if tuple([x['name'], x['campaign_id']]) in as_and_cam
        ]
        return asids

    def create_campaign(self, campaign_name, objective, status, spend_cap):
        if not self.cam_dict:
            self.set_id_name_dict(Campaign)
        if campaign_name in ([x['name'] for x in self.cam_dict]):
            logging.warning(campaign_name + ' already in account.  This ' +
                            'campaign was not uploaded.')
            return None
        self.campaign = Campaign(parent_id=self.account.get_id_assured())
        self.campaign.update({
            Campaign.Field.name: campaign_name,
            Campaign.Field.objective: objective,
            Campaign.Field.effective_status: status,
            Campaign.Field.spend_cap: int(spend_cap),
            Campaign.Field.special_ad_categories: 'NONE'
        })
        self.campaign.remote_create()

    @staticmethod
    def geo_target_search(geos):
        all_geos = []
        for geo in geos:
            params = {
                'q': geo,
                'type': 'adgeolocation',
                'location_types': [Targeting.Field.country],
            }
            resp = TargetingSearch.search(params=params)
            all_geos.extend(resp)
        return all_geos

    @staticmethod
    def target_search(targets_to_search):
        all_targets = []
        for target in targets_to_search[1]:
            params = {
                'q': target,
                'type': 'adinterest',
            }
            resp = TargetingSearch.search(params=params)
            if not resp:
                logging.warning(target + ' not found in targeting search.  ' +
                                'It was not added to the adset.')
                continue
            if targets_to_search[0] == 'interest':
                resp = [resp[0]]
            new_tar = [dict((k, x[k]) for k in ('id', 'name')) for x in resp]
            all_targets.extend(new_tar)
        return all_targets

    @staticmethod
    def get_matching_saved_audiences(audiences):
        aud_list = []
        for audience in audiences:
            audience = CustomAudience(audience)
            val_aud = audience.remote_read(fields=['targeting'])
            aud_list.append(val_aud)
            aud_list = aud_list[0]['targeting']
        return aud_list

    def get_matching_custom_audiences(self, audiences):
        act_auds = self.account.get_custom_audiences(
            fields=[CustomAudience.Field.name, CustomAudience.Field.id])
        audiences = [{
            'id': x['id'],
            'name': x['name']
        } for x in act_auds if x['id'] in audiences]
        return audiences

    def set_target(self, geos, targets, age_min, age_max, gender, device,
                   publisher_platform, facebook_positions):
        targeting = {}
        if geos and geos != ['']:
            targeting[Targeting.Field.geo_locations] = {
                Targeting.Field.countries: geos
            }
        if age_min:
            targeting[Targeting.Field.age_min] = age_min
        if age_max:
            targeting[Targeting.Field.age_max] = age_max
        if gender:
            targeting[Targeting.Field.genders] = gender
        if device and device != ['']:
            targeting[Targeting.Field.device_platforms] = device
        if publisher_platform and publisher_platform != ['']:
            targeting[Targeting.Field.publisher_platforms] = publisher_platform
        if facebook_positions and facebook_positions != ['']:
            targeting[Targeting.Field.facebook_positions] = facebook_positions
        for target in targets:
            if target[0] == 'interest' or target[0] == 'interest-broad':
                int_targets = self.target_search(target)
                targeting[Targeting.Field.interests] = int_targets
            if target[0] == 'savedaudience':
                aud_target = self.get_matching_saved_audiences(target[1])
                targeting.update(aud_target)
            if target[0] == 'customaudience':
                aud_target = self.get_matching_custom_audiences(target[1])
                targeting[Targeting.Field.custom_audiences] = aud_target
        return targeting

    def create_adset(self, adset_name, cids, opt_goal, bud_type, bud_val,
                     bill_evt, bid_amt, status, start_time, end_time, prom_obj,
                     country, target, age_min, age_max, genders, device, pubs,
                     pos):
        if not self.adset_dict:
            self.set_id_name_dict(AdSet)
        for cid in cids:
            if adset_name in ([
                    x['name'] for x in self.adset_dict
                    if x['campaign_id'] == cid
            ]):
                logging.warning(adset_name + ' already in campaign.  This ' +
                                'ad set was not uploaded.')
                continue
            targeting = self.set_target(country, target, age_min, age_max,
                                        genders, device, pubs, pos)
            params = {
                AdSet.Field.name: adset_name,
                AdSet.Field.campaign_id: cid,
                AdSet.Field.billing_event: bill_evt,
                AdSet.Field.status: status,
                AdSet.Field.targeting: targeting,
                AdSet.Field.start_time: start_time,
                AdSet.Field.end_time: end_time,
            }
            if bid_amt == '':
                params['bid_strategy'] = 'LOWEST_COST_WITHOUT_CAP'
            else:
                params[AdSet.Field.bid_amount] = int(bid_amt)
            if opt_goal in [
                    'CONTENT_VIEW', 'SEARCH', 'ADD_TO_CART', 'ADD_TO_WISHLIST',
                    'INITIATED_CHECKOUT', 'ADD_PAYMENT_INFO', 'PURCHASE',
                    'LEAD', 'COMPLETE_REGISTRATION'
            ]:
                if not self.pixel:
                    pixel = self.account.get_ads_pixels()
                    self.pixel = pixel[0]['id']
                params[AdSet.Field.promoted_object] = {
                    'pixel_id': self.pixel,
                    'custom_event_type': opt_goal,
                    'page_id': prom_obj
                }
            elif 'APP_INSTALLS' in opt_goal:
                opt_goal = opt_goal.split('|')
                params[AdSet.Field.promoted_object] = {
                    'application_id': opt_goal[1],
                    'object_store_url': opt_goal[2],
                }
            else:
                params[AdSet.Field.optimization_goal] = opt_goal
                params[AdSet.Field.promoted_object] = {'page_id': prom_obj}
            if bud_type == 'daily':
                params[AdSet.Field.daily_budget] = int(bud_val)
            elif bud_type == 'lifetime':
                params[AdSet.Field.lifetime_budget] = int(bud_val)
            self.account.create_ad_set(params=params)

    def upload_creative(self, creative_class, image_path):
        cre = creative_class(parent_id=self.account.get_id_assured())
        if creative_class == AdImage:
            cre[AdImage.Field.filename] = image_path
            cre.remote_create()
            creative_hash = cre.get_hash()
        elif creative_class == AdVideo:
            cre[AdVideo.Field.filepath] = image_path
            cre.remote_create()
            creative_hash = cre.get_id()
        else:
            creative_hash = None
        return creative_hash

    def get_all_thumbnails(self, vid):
        video = AdVideo(vid)
        thumbnails = video.get_thumbnails()
        if not thumbnails:
            logging.warning('Could not retrieve thumbnail for vid: ' +
                            str(vid) + '.  Retrying in 120s.')
            time.sleep(120)
            thumbnails = self.get_all_thumbnails(vid)
        return thumbnails

    def get_video_thumbnail(self, vid):
        thumbnails = self.get_all_thumbnails(vid)
        thumbnail = [x for x in thumbnails if x['is_preferred'] is True]
        if not thumbnail:
            thumbnail = thumbnails[1]
        else:
            thumbnail = thumbnail[0]
        thumb_url = thumbnail['uri']
        return thumb_url

    @staticmethod
    def request_error(e):
        if e._api_error_code == 2:
            logging.warning(
                'Retrying as the call resulted in the following: ' + str(e))
        else:
            logging.error('Retrying in 120 seconds as the Facebook API call'
                          'resulted in the following error: ' + str(e))
            time.sleep(120)

    def create_ad(self,
                  ad_name,
                  asids,
                  title,
                  body,
                  desc,
                  cta,
                  durl,
                  url,
                  prom_obj,
                  ig_id,
                  view_tag,
                  ad_status,
                  creative_hash=None,
                  vid_id=None):
        if not self.ad_dict:
            self.set_id_name_dict(Ad)
        for asid in asids:
            if ad_name in [
                    x['name'] for x in self.ad_dict
                    if x['campaign_id'] == asid[1] and x['adset_id'] == asid[0]
            ]:
                logging.warning(ad_name + ' already in campaign/adset. ' +
                                'This ad was not uploaded.')
                continue
            if vid_id:
                params = self.get_video_ad_params(ad_name, asid, title, body,
                                                  desc, cta, url, prom_obj,
                                                  ig_id, creative_hash, vid_id,
                                                  view_tag, ad_status)
            elif isinstance(creative_hash, list):
                params = self.get_carousel_ad_params(ad_name, asid, title,
                                                     body, desc, cta, durl,
                                                     url, prom_obj, ig_id,
                                                     creative_hash, view_tag,
                                                     ad_status)
            else:
                params = self.get_link_ad_params(ad_name, asid, title, body,
                                                 desc, cta, durl, url,
                                                 prom_obj, ig_id,
                                                 creative_hash, view_tag,
                                                 ad_status)
            for attempt_number in range(100):
                try:
                    self.account.create_ad(params=params)
                    break
                except FacebookRequestError as e:
                    self.request_error(e)

    def get_video_ad_params(self, ad_name, asid, title, body, desc, cta, url,
                            prom_obj, ig_id, creative_hash, vid_id, view_tag,
                            ad_status):
        data = self.get_video_ad_data(vid_id, body, title, desc, cta, url,
                                      creative_hash)
        story = {
            AdCreativeObjectStorySpec.Field.page_id: str(prom_obj),
            AdCreativeObjectStorySpec.Field.video_data: data
        }
        if ig_id and str(ig_id) != 'nan':
            story[AdCreativeObjectStorySpec.Field.instagram_actor_id] = ig_id
        creative = {AdCreative.Field.object_story_spec: story}
        params = {
            Ad.Field.name: ad_name,
            Ad.Field.status: ad_status,
            Ad.Field.adset_id: asid[0],
            Ad.Field.creative: creative
        }
        if view_tag and str(view_tag) != 'nan':
            params['view_tags'] = [view_tag]
        return params

    def get_link_ad_params(self, ad_name, asid, title, body, desc, cta, durl,
                           url, prom_obj, ig_id, creative_hash, view_tag,
                           ad_status):
        data = self.get_link_ad_data(body, creative_hash, durl, desc, url,
                                     title, cta)
        story = {
            AdCreativeObjectStorySpec.Field.page_id: str(prom_obj),
            AdCreativeObjectStorySpec.Field.link_data: data
        }
        if ig_id and str(ig_id) != 'nan':
            story[AdCreativeObjectStorySpec.Field.instagram_actor_id] = ig_id
        creative = {AdCreative.Field.object_story_spec: story}
        params = {
            Ad.Field.name: ad_name,
            Ad.Field.status: ad_status,
            Ad.Field.adset_id: asid[0],
            Ad.Field.creative: creative
        }
        if view_tag and str(view_tag) != 'nan':
            params['view_tags'] = [view_tag]
        return params

    @staticmethod
    def get_video_ad_data(vid_id, body, title, desc, cta, url, creative_hash):
        data = {
            AdCreativeVideoData.Field.video_id: vid_id,
            AdCreativeVideoData.Field.message: body,
            AdCreativeVideoData.Field.title: title,
            AdCreativeVideoData.Field.link_description: desc,
            AdCreativeVideoData.Field.call_to_action: {
                'type': cta,
                'value': {
                    'link': url,
                },
            },
        }
        if creative_hash[:4] == 'http':
            data[AdCreativeVideoData.Field.image_url] = creative_hash
        else:
            data[AdCreativeVideoData.Field.image_hash] = creative_hash
        return data

    @staticmethod
    def get_link_ad_data(body, creative_hash, durl, desc, url, title, cta):
        data = {
            AdCreativeLinkData.Field.message: body,
            AdCreativeLinkData.Field.image_hash: creative_hash,
            AdCreativeLinkData.Field.caption: durl,
            AdCreativeLinkData.Field.description: desc,
            AdCreativeLinkData.Field.link: url,
            AdCreativeLinkData.Field.name: title,
            AdCreativeLinkData.Field.call_to_action: {
                'type': cta,
                'value': {
                    'link': url,
                },
            },
        }
        return data

    @staticmethod
    def get_carousel_ad_data(creative_hash,
                             desc,
                             url,
                             title,
                             cta,
                             vid_id=None):
        data = {
            AdCreativeLinkData.Field.description: desc,
            AdCreativeLinkData.Field.link: url,
            AdCreativeLinkData.Field.name: title,
            AdCreativeLinkData.Field.call_to_action: {
                'type': cta,
                'value': {
                    'link': url,
                },
            },
        }
        if creative_hash[:4] == 'http':
            data['picture'] = creative_hash
        else:
            data[AdCreativeVideoData.Field.image_hash] = creative_hash
        if vid_id:
            data[AdCreativeVideoData.Field.video_id] = vid_id
        return data

    @staticmethod
    def get_individual_carousel_param(param_list, idx):
        if idx < len(param_list):
            param = param_list[idx]
        else:
            logging.warning('{} does not have index {}.  Using last available.'
                            ''.format(param_list, idx))
            param = param_list[-1]
        return param

    def get_carousel_ad_params(self, ad_name, asid, title, body, desc, cta,
                               durl, url, prom_obj, ig_id, creative_hash,
                               view_tag, ad_status):
        data = []
        for idx, creative in enumerate(creative_hash):
            current_description = self.get_individual_carousel_param(desc, idx)
            current_url = self.get_individual_carousel_param(url, idx)
            current_title = self.get_individual_carousel_param(title, idx)
            if len(creative) == 1:
                data_ind = self.get_carousel_ad_data(creative_hash=creative[0],
                                                     desc=current_description,
                                                     url=current_url,
                                                     title=current_title,
                                                     cta=cta)
            else:
                data_ind = self.get_carousel_ad_data(creative_hash=creative[1],
                                                     desc=current_description,
                                                     url=current_url,
                                                     title=current_title,
                                                     cta=cta,
                                                     vid_id=creative[0])
            data.append(data_ind)
        link = {
            AdCreativeLinkData.Field.message: body,
            AdCreativeLinkData.Field.link: url[0],
            AdCreativeLinkData.Field.caption: durl,
            AdCreativeLinkData.Field.child_attachments: data,
            AdCreativeLinkData.Field.call_to_action: {
                'type': cta,
                'value': {
                    'link': url[0],
                },
            },
        }
        story = {
            AdCreativeObjectStorySpec.Field.page_id: str(prom_obj),
            AdCreativeObjectStorySpec.Field.link_data: link
        }
        if ig_id and str(ig_id) != 'nan':
            story[AdCreativeObjectStorySpec.Field.instagram_actor_id] = ig_id
        creative = {AdCreative.Field.object_story_spec: story}
        params = {
            Ad.Field.name: ad_name,
            Ad.Field.status: ad_status,
            Ad.Field.adset_id: asid[0],
            Ad.Field.creative: creative
        }
        if view_tag and str(view_tag) != 'nan':
            params['view_tags'] = [view_tag]
        return params
Beispiel #11
0
def get_add_sets(app_id: str, app_secret: str, account_access_token: str,
                 account_id: str):
    FacebookAdsApi.init(app_id, app_secret, account_access_token)
    account = AdAccount(account_id)
    return account.get_ad_sets()