def get_ads(mmt_ads_acct): ad_params = { 'fields': [Ad.Field.adset_id, Ad.Field.id, 'creative{object_story_spec}'], 'limit': 500, 'filtering': [{ 'field': 'ad.effective_status', 'operator': AdsInsights.Operator.in_, 'value': [ Ad.EffectiveStatus.active, # Ad.EffectiveStatus.adset_paused, Ad.EffectiveStatus.campaign_paused, Ad.EffectiveStatus.paused ] }] } try: ads_generator = mmt_ads_acct.get_ads(params=ad_params) return {ad[AdsInsights.Field.adset_id]: ad for ad in ads_generator} except FacebookRequestError as e: if e.api_error_code() == 17: err('A: Hit api limit..backing off') time.sleep(60) return get_ads(mmt_ads_acct) else: raise e
def get_adsets(mmt_ads_acct, adset_ids, ts): adset_params = { 'fields': [ AdSet.Field.name, AdSet.Field.created_time, AdSet.Field.start_time, AdSet.Field.end_time, AdSet.Field.effective_status, AdSet.Field.budget_remaining, AdSet.Field.daily_budget, AdSet.Field.lifetime_budget, AdSet.Field.id ], 'filtering': [{ 'field': AdSet.Field.id, 'operator': 'IN', 'value': list(adset_ids) }], 'limit': 500 } try: adsets_generator = mmt_ads_acct.get_ad_sets(params=adset_params) adsets = {adset[AdSet.Field.id]: adset for adset in adsets_generator} except FacebookRequestError as e: if e.api_error_code() == 17: err('AS: Hit api limit..backing off') time.sleep(60) return get_adsets(mmt_ads_acct, adset_ids, ts) else: raise e remove_adsets = [] for adset_id in adsets: start_date = adsets[adset_id][AdSet.Field.start_time] end_date = adsets[adset_id][AdSet.Field.end_time] if get_datetime(ts) > get_datetime(end_date): print('{} already ended on {}'.format(adset_id, end_date)) remove_adsets.append(adset_id) elif get_datetime(ts) < get_datetime(start_date): print('{} has not started yet, starts on {}'.format( adset_id, start_date)) remove_adsets.append(adset_id) for adset_id in remove_adsets: adsets.pop(adset_id) return adsets
def get_reach_estimate(adset): try: adset.remote_read(fields=['delivery_estimate']) except FacebookRequestError as e: if e.api_error_code() == 17: err('RE: reached api limit') time.sleep(60) return get_reach_estimate(adset) else: raise e reach_estimate = -1 try: data = adset['delivery_estimate']['data'] if 'data' in adset[ 'delivery_estimate'] else [] reach_estimate = data[0]['estimate_mau'] except (KeyError, IndexError): pass return reach_estimate
def find_my_fbid(search_term, quiet=True): """ Tries to find a valid facebook page id for a search term (ie url) Args: search_term: url, canonical name, etc to search for fbid quiet: don't emit error Returns: valid fbid for search_term, or None """ try: resp = requests.post('https://findmyfbid.com', data={'url': search_term}) resp.raise_for_status() fbid = json.loads(resp.text)['id'] except Exception as e: if not quiet: from workbench.core.utils import err err(e) return None return fbid
def get_adset_period_insight(adset, start_date, end_date): period_insight_parameters = { 'fields': [ AdsInsights.Field.reach, AdsInsights.Field.frequency, AdsInsights.Field.actions, AdsInsights.Field.date_start, AdsInsights.Field.date_stop ], 'time_ranges': [{ 'since': tsify_datetime(start_date), 'until': tsify_datetime(end_date) }] } try: return adset.get_insights(params=period_insight_parameters) except FacebookRequestError as e: if e.api_error_code() == 17: err('ASPI: Hit api limit..backing off') time.sleep(60) return get_adset_period_insight(adset, start_date, end_date) else: raise e
def process_trends_model_input(fn, curs=None): """ Processes flat file input into list of artist X locations Input is line-separated artist names, or 4-space delimited/line-separated artist names + nation isos Args: fn: full path to input file curs: a Redshift cursor to use (if needed) Returns: [{'name': <artist name>, 'location': <nation iso>, ...}, ...] """ try: with open(fn, 'r') as f: raw = [l.rstrip().replace('!', '') for l in f.readlines()] assert len(raw) > 0 and all(len(raw_inp) > 0 for raw_inp in raw) except FileNotFoundError: raise ProcessError( 'no such file {} (hint: must be absolute path)'.format(fn)) except AssertionError: raise ProcessError( 'file {} was empty or contained empty lines'.format(fn)) if len(raw[0].split(TRENDS_SEPERATOR)) > 1: return [ dict(zip(('name', 'location'), l.split(TRENDS_SEPERATOR))) for l in raw ] else: curs = curs or get_redshift_cursor() try: curs.execute(NATIONS_STMT) except Exception as e: err(e) raise ProcessError('failed to fetch whitelist biz dev nations') locs = [loc for loc in curs.fetchall()] return [ dict(name=raw_artist, location=loc[0]) for raw_artist in raw for loc in locs ]
def filter_by_facebook_likes(artists_and_locations, min_likes_threshold=5000, curs=None): """ Args: artists_and_locations: [{'name': <artist name>, 'location': <nation iso>, ...}, ...] min_likes_threshold: minimum facebook likes to filter by curs: a Redshift cursor to use Returns: filtered by limit, [{'name': <artist name>, 'location': <nation iso>, ...}, ...] """ curs = curs or get_redshift_cursor() try: artist_names = set( map(lambda a_l: a_l['name'].lower(), artists_and_locations)) locations = set(map(lambda a_l: a_l['location'], artists_and_locations)) except KeyError as e: err(e) raise ProcessError( 'artists_and_locations must be: ' '[{\'name\': <artist name>, \'location\': <nation iso>, ...}, ...]' ) try: curs.execute( FILTER_STMT, (min_likes_threshold, tuple(locations), tuple(artist_names))) except Exception as e: err(e) raise ProcessError('filter query failed') filter_by = set( '_'.join([str(row[0].lower()), str(row[1])]) for row in curs.fetchall()) return list( filter( lambda a_l: '_'.join([a_l['name'].lower(), a_l['location']]) in filter_by, artists_and_locations))
def get_adset_insights(mmt_ads_acct, adset_ids, ts): insight_params = { 'level': AdsInsights.Level.adset, 'fields': [ AdsInsights.Field.adset_id, AdsInsights.Field.reach, AdsInsights.Field.cpp, AdsInsights.Field.frequency, AdsInsights.Field.spend, AdsInsights.Field.actions, AdsInsights.Field.cost_per_action_type ], 'filtering': [{ 'field': 'adset.id', 'operator': AdsInsights.Operator.in_, 'value': list(adset_ids) }], 'time_ranges': [{ 'since': tsify_datetime(ts), 'until': tsify_datetime(ts) }], 'limit': 500 } try: insight_generator = mmt_ads_acct.get_insights(params=insight_params) return { insight[AdsInsights.Field.adset_id]: insight for insight in insight_generator } except FacebookRequestError as e: if e.api_error_code() == 17: err('ASI: Hit api limit..backing off') time.sleep(60) return get_adset_insights(mmt_ads_acct, adset_ids, ts) else: raise e