Facebook营销API - 使用Python获取洞察数据 - 用户请求限制已达上限

11

所以我正在努力学习如何使用Facebook API。我需要创建一个脚本,每天将我的业务广告系列的信息下载为csv文件,以便我可以使用另一个脚本轻松地将信息上传到我们的数据库。

我终于有了可用于将信息打印到日志中的代码,但由于我必须为每个广告系列单独调用get_insights()方法,因此我已经达到了用户请求限制。我想知道是否有人知道如何帮助我减少调用Facebook API的频率。

如果可能的话,我想找到一个可以获取每日花费的字段,这样我就不必在每次广告系列循环迭代中都调用API,但是我无论如何都找不到方法。

#Import all the facebook mumbo jumbo
from facebookads.api import FacebookAdsApi
from facebookads.adobjects.adset import AdSet
from facebookads.adobjects.campaign import Campaign
from facebookads.adobjects.adsinsights import AdsInsights
from facebookads.adobjects.adreportrun import AdReportRun
from facebookads.adobjects.adaccount import AdAccount
from facebookads.adobjects.business import Business
import time

#Set the login info
my_app_id = '****'
my_app_secret = '****'
my_access_token = '****'

#Start the connection to the facebook API
FacebookAdsApi.init(my_app_id, my_app_secret, my_access_token)

business = Business('****')

#Get all ad accounts on the business account 
accounts = business.get_owned_ad_accounts(fields=[AdAccount.Field.id])

#iterate through all accounts in the business account
for account in accounts:
    tempaccount = AdAccount(account[AdAccount.Field.id])
    #get all campaigns in the adaccount
    campaigns = tempaccount.get_campaigns(fields=[Campaign.Field.name,Campaign.Field])
    #iterate trough all the campaigns in the adaccount
    for campaign in campaigns:
        print(campaign[Campaign.Field.name])
        #get the insight info (spend) from each campaign
        campaignsights = campaign.get_insights(params={'date_preset':'yesterday'},fields=[AdsInsights.Field.spend])
        print (campaignsights)
3个回答

22

我翻了一会儿API,猜了一下,但终于搞定了!这是我的最终脚本:

# This program downloads all relevent Facebook traffic info as a csv file
# This program requires info from the Facebook Ads API: https://github.com/facebook/facebook-python-ads-sdk

# Import all the facebook mumbo jumbo
from facebookads.api import FacebookAdsApi
from facebookads.adobjects.adsinsights import AdsInsights
from facebookads.adobjects.adaccount import AdAccount
from facebookads.adobjects.business import Business

# Import th csv writer and the date/time function
import datetime
import csv

# Set the info to get connected to the API. Do NOT share this info
my_app_id = '****'
my_app_secret = '****'
my_access_token = '****'

# Start the connection to the facebook API
FacebookAdsApi.init(my_app_id, my_app_secret, my_access_token)

# Create a business object for the business account
business = Business('****')

# Get yesterday's date for the filename, and the csv data
yesterdaybad = datetime.datetime.now() - datetime.timedelta(days=1)
yesterdayslash = yesterdaybad.strftime('%m/%d/%Y')
yesterdayhyphen = yesterdaybad.strftime('%m-%d-%Y')

# Define the destination filename
filename = yesterdayhyphen + '_fb.csv'
filelocation = "/cron/downloads/"+ filename

# Get all ad accounts on the business account
accounts = business.get_owned_ad_accounts(fields=[AdAccount.Field.id])

# Open or create new file 
try:
    csvfile = open(filelocation , 'w+', 0777)
except:
    print ("Cannot open file.")


# To keep track of rows added to file
rows = 0

try:
    # Create file writer
    filewriter = csv.writer(csvfile, delimiter=',')
except Exception as err:
    print(err)

# Iterate through the adaccounts
for account in accounts:
    # Create an addaccount object from the adaccount id to make it possible to get insights
    tempaccount = AdAccount(account[AdAccount.Field.id])

    # Grab insight info for all ads in the adaccount
    ads = tempaccount.get_insights(params={'date_preset':'yesterday',
                                           'level':'ad'
                                          },
                                   fields=[AdsInsights.Field.account_id,
                       AdsInsights.Field.account_name,
                                           AdsInsights.Field.ad_id,
                                           AdsInsights.Field.ad_name,
                                           AdsInsights.Field.adset_id,
                                           AdsInsights.Field.adset_name,
                                           AdsInsights.Field.campaign_id,
                                           AdsInsights.Field.campaign_name,
                                           AdsInsights.Field.cost_per_outbound_click,
                                           AdsInsights.Field.outbound_clicks,
                                           AdsInsights.Field.spend
                                          ]
    );

    # Iterate through all accounts in the business account
    for ad in ads:
        # Set default values in case the insight info is empty
        date = yesterdayslash
        accountid = ad[AdsInsights.Field.account_id]
        accountname = ""
        adid = ""
        adname = ""
        adsetid = ""
        adsetname = ""
        campaignid = ""
        campaignname = ""
        costperoutboundclick = ""
        outboundclicks = ""
        spend = ""

        # Set values from insight data
        if ('account_id' in ad) :
            accountid = ad[AdsInsights.Field.account_id]
        if ('account_name' in ad) :
            accountname = ad[AdsInsights.Field.account_name]
        if ('ad_id' in ad) :
            adid = ad[AdsInsights.Field.ad_id]
        if ('ad_name' in ad) :
            adname = ad[AdsInsights.Field.ad_name]
        if ('adset_id' in ad) :
            adsetid = ad[AdsInsights.Field.adset_id]
        if ('adset_name' in ad) :
            adsetname = ad[AdsInsights.Field.adset_name]
        if ('campaign_id' in ad) :
            campaignid = ad[AdsInsights.Field.campaign_id]
        if ('campaign_name' in ad) :
            campaignname = ad[AdsInsights.Field.campaign_name]
        if ('cost_per_outbound_click' in ad) : # This is stored strangely, takes a few steps to break through the layers
            costperoutboundclicklist = ad[AdsInsights.Field.cost_per_outbound_click]
            costperoutboundclickdict = costperoutboundclicklist[0]
            costperoutboundclick = costperoutboundclickdict.get('value')
        if ('outbound_clicks' in ad) : # This is stored strangely, takes a few steps to break through the layers
            outboundclickslist = ad[AdsInsights.Field.outbound_clicks]
            outboundclicksdict = outboundclickslist[0]
            outboundclicks = outboundclicksdict.get('value')
        if ('spend' in ad) :
            spend = ad[AdsInsights.Field.spend]

        # Write all ad info to the file, and increment the number of rows that will display
        filewriter.writerow([date, accountid, accountname, adid, adname, adsetid, adsetname, campaignid, campaignname, costperoutboundclick, outboundclicks, spend])
        rows += 1


csvfile.close()

# Print report
print (str(rows) + " rows added to the file " + filename)

我随后使用一个PHP脚本将CSV文件上传到我的数据库。关键在于一次性获取所有的见解数据。然后,由于每个广告都包含有关其广告集、广告账户和广告系列的信息,因此您可以按任何方式对其进行拆分。


5
你不知道这篇文章对我有多大帮助。当通过各种SDK发出请求时,如何访问字段上的数据并不明显。我一直回到这篇文章,因为我没找到任何其他清晰记录此内容的来源。 - Marks Andre
1
非常感谢您! - helloworld
业务对象实例中包含什么,即 '***'?我的天啊,Facebook_business SDK 简直是噩梦... 没有文档字符串。 - Marco Fumagalli
@MarcoFumagalli 您的业务ID - LucyTurtle
1
请问有人已经遇到以下错误了吗: 信息:调用不成功 方法:GET 路径:https://graph.facebook.com/v2.11/act_**********/owned_ad_accounts 参数:{'fields': 'id', 'summary': 'true'} 状态:400 响应: { "error": { "message": "(#2635) You are calling a deprecated version of the Ads API. Please update to the latest version: v8.0.", "type": "OAuthException", "code": 2635, "fbtrace_id": "***********" } } - Mohamed Azizi
@MohamedAzizi 听起来你正在使用过时的 API 版本。请将链接从 graph.facebook.com/v2.11/act_ 更改为 graph.facebook.com/v8.0/act_。 - LucyTurtle

6

在LucyTurtle的答案基础上添加几个小功能,以改进其对Facebook速率限制的容忍性。

import logging
import requests as rq

#Function to find the string between two strings or characters
def find_between( s, first, last ):
    try:
        start = s.index( first ) + len( first )
        end = s.index( last, start )
        return s[start:end]
    except ValueError:
        return ""

#Function to check how close you are to the FB Rate Limit
def check_limit():
    def check_limit():
    check=rq.get('https://graph.facebook.com/v3.3/act_'+account_number+'/insights?access_token='+my_access_token)
    call=float(find_between(check.headers['x-business-use-case-usage'],'call_count":','}'))
    cpu=float(find_between(check.headers['x-business-use-case-usage'],'total_cputime":','}'))
    total=float(find_between(check.headers['x-business-use-case-usage'],'total_time":',','))
    usage=max(call,cpu,total)
    return usage

#Check if you reached 75% of the limit, if yes then back-off for 5 minutes (put this chunk in your 'for ad is ads' loop, every 100-200 iterations)
if (check_limit()>75):
    print('75% Rate Limit Reached. Cooling Time 5 Minutes.')
    logging.debug('75% Rate Limit Reached. Cooling Time 5 Minutes.')
    time.sleep(300)

我相信你想要写的是:if (check_limit()>75): - helloworld
是的,谢谢 @helloworld - Ashish Baid
随时查看我的帖子,我在那里标记了你:https://stackoverflow.com/a/55537459/11050796 - helloworld

0

我只想说 谢谢。 正如Marks Andre所说 - 你让我的一天! FB SDK文档非常详尽,但它完全缺乏日常任务的实际实现示例,比如这个。书签已设置 - 页面很快就会重新访问。

因此,我唯一能为同样遭受痛苦的人做出的贡献是:似乎使用更新的facebook_business SDK,您可以简单地将导入语句中的“facebookads”完全替换为“facebook_business”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接