Closed FAKERBNZ closed 3 years ago
this seems to me your request failed during oauth. did you try get refreshtoken/accesstoken with msads.manage scope?
this seems to me your request failed during oauth. did you try get refreshtoken/accesstoken with msads.manage scope?
yes i can refresh token with soap requests and i even can get campaigns with soap requests but when i try to get ad spend with reporting api i fail wih python sdk and with soap requests with 'invalid client data error'
Can you please share the trackingid/requestid of the failed call?
_: 'Invalid client data. Check the SOAP fault details for more information. TrackingId: da934449-3f4f-4481-b29a-71e08e4ce65d.', thank you
@FakerBZD thanks, will ask the corresponding team for double check.
@FakerBZD , per the trackingid: your access token is expired. could you please share your code on how to calling the reporting api?
i can get campains id with the same token and we are refreshing it successfully every 5 min
SOAP request
<s:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header xmlns="https://bingads.microsoft.com/Reporting/v13">
<Action mustUnderstand="1">SubmitGenerateReport</Action>
<AuthenticationToken i:nil="false">{accessToken}</AuthenticationToken>
<CustomerAccountId i:nil="false">AdvertiserAccount.Id</CustomerAccountId>
<CustomerId i:nil="false">AdvertiserAccount.ParentCustomerId</CustomerId>
<DeveloperToken i:nil="false">{devToken}</DeveloperToken>
</s:Header>
<s:Body>
<SubmitGenerateReportRequest xmlns="https://bingads.microsoft.com/Reporting/v13">
<ReportRequest i:nil="false" i:type="AccountPerformanceReportRequest">
<ExcludeColumnHeaders i:nil="false">false</ExcludeColumnHeaders>
<ExcludeReportFooter i:nil="false">true</ExcludeReportFooter>
<ExcludeReportHeader i:nil="false">false</ExcludeReportHeader>
<Format i:nil="false">Csv</Format>
<FormatVersion i:nil="false"> 1.0</FormatVersion>
<ReportName i:nil="false">AdSpend report</ReportName>
<ReturnOnlyCompleteData i:nil="false">false</ReturnOnlyCompleteData>
<Aggregation>Daily</Aggregation>
<Columns i:nil="false">
<CampaignPerformanceReportColumn>Spend</CampaignPerformanceReportColumn>
</Columns>
< <Filter i:nil="true" />
<Scope i:nil="false">
<AccountIds i:nil="false" xmlns:a1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a1:long>AdvertiserAccount.Id</a1:long>
</AccountIds>
<Campaigns i:nil="false">
<CampaignReportScope>
<AccountId>AdvertiserAccount.Id</AccountId>
<CampaignId>CampaignId</CampaignId>
</CampaignReportScope>
</Campaigns>
</Scope>
<Time i:nil="false">
<CustomDateRangeEnd i:nil="false">
<Day>20</Day>
<Month>6</Month>
<Year>2021</Year>
</CustomDateRangeEnd>
<CustomDateRangeStart i:nil="false">
<Day>1</Day>
<Month>1</Month>
<Year>2018</Year>
</CustomDateRangeStart>
<PredefinedTime i:nil="true" />
<ReportTimeZone i:nil="true" />
</Time>
</ReportRequest>
</SubmitGenerateReportRequest>
</s:Body>
</s:Envelope>
the soap request failed
the python report request
#!/usr/bin/python3
import sys
import io
import pandas as pd
from urllib import parse
from datetime import datetime, timedelta
from bingads.service_client import ServiceClient
from bingads.v13 import *
from bingads.v13.reporting import *
from suds import WebFault
from suds.client import Client
#Function for date validation
def date_validation(date_text):
try:
while date_text != datetime.strptime(date_text, '%Y-%m-%d').strftime('%Y-%m-%d'):
date_text = input('Please Enter the date in YYYY-MM-DD format\t')
else:
return datetime.strptime(date_text,'%Y-%m-%d').date()
except:
raise Exception('linkedin_campaign_processing : year does not match format yyyy-mm-dd')
def get_campaign_report(authorization_data,account_id,s_date,e_date,qry_type):
try:
startDate = date_validation(s_date)
dt = startDate+timedelta(1)
week_number = dt.isocalendar()[1]
endDate = date_validation(e_date)
reporting_service = ServiceClient(
service='ReportingService',
version=13,
authorization_data=authorization_data,
environment='production',
)
if qry_type in ["day","daily"]:
aggregation = 'Daily'
elif qry_type in ["week","weekly"]:
aggregation = 'Weekly'
exclude_column_headers=False
exclude_report_footer=False
exclude_report_header=False
time=reporting_service.factory.create('ReportTime')
# You can either use a custom date range or predefined time.
#time.PredefinedTime='Yesterday'
start_date=reporting_service.factory.create('Date')
start_date.Day=startDate.day
start_date.Month=startDate.month
start_date.Year=startDate.year
time.CustomDateRangeStart=start_date
end_date=reporting_service.factory.create('Date')
end_date.Day=endDate.day
end_date.Month=endDate.month
end_date.Year=endDate.year
time.CustomDateRangeEnd=end_date
time.ReportTimeZone='PacificTimeUSCanadaTijuana'
return_only_complete_data=False
report_request=reporting_service.factory.create('CampaignPerformanceReportRequest')
report_request.Aggregation=aggregation
report_request.ExcludeColumnHeaders=exclude_column_headers
report_request.ExcludeReportFooter=exclude_report_footer
report_request.ExcludeReportHeader=exclude_report_header
report_request.Format='Csv'
report_request.ReturnOnlyCompleteData=return_only_complete_data
report_request.Time=time
report_request.ReportName="Campaign Performance Report"
scope=reporting_service.factory.create('AccountThroughCampaignReportScope')
scope.AccountIds={'long': [account_id] }
scope.Campaigns=None
report_request.Scope=scope
report_columns=reporting_service.factory.create('ArrayOfCampaignPerformanceReportColumn')
report_columns.CampaignPerformanceReportColumn.append(['AccountName','AccountId','TimePeriod','CampaignId',
'CampaignName','Impressions','Clicks','Conversions' ,'Spend'])
report_request.Columns=report_columns
#return campaign_performance_report_request
return report_request
except:
print("\nMS_ADS_CAMPAIGN_REPORT : report processing Failed : ", sys.exc_info())
def download_campaign_report(report_request,authorization_data,s_date,e_date,qry_type):
try:
startDate = date_validation(s_date)
dt = startDate+timedelta(1)
week_number = dt.isocalendar()[1]
endDate = date_validation(e_date)
reporting_download_parameters = ReportingDownloadParameters(
report_request=report_request,
result_file_directory = "./data/",
result_file_name = "campaign_report.csv",
overwrite_result_file = True, # value true if you want to overwrite the same file.
timeout_in_milliseconds=3600000 # cancel the download after a specified time interval.
)
reporting_service_manager=ReportingServiceManager(
authorization_data=authorization_data,
poll_interval_in_milliseconds=5000,
environment='production',
)
report_container = reporting_service_manager.download_report(reporting_download_parameters)
if(report_container == None):
print("There is no report data for the submitted report request parameters.")
sys.exit(0)
campaign_analytics_data = pd.DataFrame(columns=["account_id","campaign_name","campaign_id","start_date","end_date",
"cost","impressions","clicks"])
if "Impressions" in report_container.report_columns and \
"Clicks" in report_container.report_columns and \
"Spend" in report_container.report_columns and \
"CampaignId" in report_container.report_columns:
report_record_iterable = report_container.report_records
for record in report_record_iterable:
tmp_dict = {}
tmp_dict["impressions"] = record.int_value("Impressions")
tmp_dict["clicks"] = record.int_value("Clicks")
tmp_dict["cost"] = float(record.value("Spend"))
#print(float(record.value("Spend")))
tmp_dict["conversions"] = record.int_value("Conversions")
tmp_dict["campaign_name"] = record.value("CampaignName")
tmp_dict["campaign_id"] = record.int_value("CampaignId")
tmp_dict["account_name"] = record.value("AccountName")
tmp_dict["account_id"] = record.int_value("AccountId")
campaign_analytics_data = campaign_analytics_data.append(tmp_dict,ignore_index = True)
campaign_analytics_data["start_date"] = startDate
campaign_analytics_data["end_date"] = endDate
if qry_type in ["week","weekly"]:
campaign_analytics_data["week"] = week_number
elif qry_type in ["month","monthly"]:
campaign_analytics_data["month"] = startDate.month
elif qry_type in ["day","daily"]:
campaign_analytics_data["week"] = week_number
#Be sure to close the report.
report_container.close()
return campaign_analytics_data
except:
print("\nDOWNLOAD_CAMPAIGN_REPORT : processing Failed : ", sys.exc_info())
def get_ads_report(authorization_data,account_id,s_date,e_date,qry_type):
try:
startDate = date_validation(s_date)
dt = startDate+timedelta(1)
week_number = dt.isocalendar()[1]
endDate = date_validation(e_date)
reporting_service = ServiceClient(
service='ReportingService',
version=13,
authorization_data=authorization_data,
environment='production',
)
if qry_type in ["day","daily"]:
aggregation = 'Daily'
elif qry_type in ["week","weekly"]:
aggregation = 'Weekly'
exclude_column_headers=False
exclude_report_footer=False
exclude_report_header=False
time=reporting_service.factory.create('ReportTime')
start_date=reporting_service.factory.create('Date')
start_date.Day=startDate.day
start_date.Month=startDate.month
start_date.Year=startDate.year
time.CustomDateRangeStart=start_date
end_date=reporting_service.factory.create('Date')
end_date.Day=endDate.day
end_date.Month=endDate.month
end_date.Year=endDate.year
time.CustomDateRangeEnd=end_date
time.ReportTimeZone='PacificTimeUSCanadaTijuana'
return_only_complete_data=False
report_request=reporting_service.factory.create('AdPerformanceReportRequest')
report_request.Aggregation=aggregation
report_request.ExcludeColumnHeaders=exclude_column_headers
report_request.ExcludeReportFooter=exclude_report_footer
report_request.ExcludeReportHeader=exclude_report_header
report_request.Format='Csv'
report_request.ReturnOnlyCompleteData=return_only_complete_data
report_request.Time=time
report_request.ReportName="Ads Performance Report"
scope=reporting_service.factory.create('AccountThroughAdGroupReportScope')
scope.AccountIds={'long': [account_id] }
scope.Campaigns=None
report_request.Scope=scope
report_columns=reporting_service.factory.create('ArrayOfAdPerformanceReportColumn')
report_columns.AdPerformanceReportColumn.append(['AccountId','TimePeriod','CampaignId',
'CampaignName','AdId','Impressions','Clicks','Conversions','Spend'])
report_request.Columns=report_columns
#return campaign_performance_report_request
return report_request
except:
print("\nMS_ADS_REPORT : report processing Failed : ", sys.exc_info())
def download_ads_report(report_request,authorization_data,s_date,e_date,qry_type):
try:
startDate = date_validation(s_date)
dt = startDate+timedelta(1)
week_number = dt.isocalendar()[1]
endDate = date_validation(e_date)
reporting_download_parameters = ReportingDownloadParameters(
report_request=report_request,
result_file_directory = "./data/",
result_file_name = "ads_report.csv",
overwrite_result_file = True, # Set this value true if you want to overwrite the same file.
timeout_in_milliseconds=3600000 # You may optionally cancel the download after a specified time interval.
)
#global reporting_service_manager
reporting_service_manager=ReportingServiceManager(
authorization_data=authorization_data,
poll_interval_in_milliseconds=5000,
environment='production',
)
report_container = reporting_service_manager.download_report(reporting_download_parameters)
if(report_container == None):
print("There is no report data for the submitted report request parameters.")
sys.exit(0)
ads_analytics_data = pd.DataFrame(columns=["account_id","campaign_name","campaign_id","start_date","end_date",
"ad_id","cost","impressions","clicks","final_url","currency"])
if "Impressions" in report_container.report_columns and \
"Clicks" in report_container.report_columns and \
"Spend" in report_container.report_columns and \
"AdId" in report_container.report_columns:
report_record_iterable = report_container.report_records
total_impressions = 0
total_clicks = 0
distinct_devices = set()
distinct_networks = set()
for record in report_record_iterable:
tmp_dict = {}
tmp_dict["impressions"] = record.int_value("Impressions")
tmp_dict["clicks"] = record.int_value("Clicks")
tmp_dict["cost"] = float(record.value("Spend"))
tmp_dict["conversions"] = record.int_value("Conversions")
tmp_dict["campaign_name"] = record.value("CampaignName")
tmp_dict["campaign_id"] = record.int_value("CampaignId")
tmp_dict["account_id"] = record.int_value("AccountId")
tmp_dict["ad_id"] = record.int_value("AdId")
tmp_dict["currency"] = record.value("CurrencyCode")
try:
utm_campaign = None
utm_source = 'bing'
o = parse.urlparse(record.value("FinalUrl"))
query_url = parse.parse_qs(o.query)
url = o._replace(query=None).geturl()
#utm_campaign = query_url["utm_campaign"][0]
#print(utm_campaign)
utm_campaign = "MS "+ record.value("CampaignName")
except:
print("\n***UTM data extraction Failed: ",sys.exc_info())
pass
tmp_dict["final_url"] = url
tmp_dict["utm_campaign"] = utm_campaign
tmp_dict["utm_source"] = utm_source
ads_analytics_data = ads_analytics_data.append(tmp_dict,ignore_index = True)
ads_analytics_data = ads_analytics_data.append(tmp_dict,ignore_index = True)
ads_analytics_data["start_date"] = startDate
ads_analytics_data["end_date"] = endDate
if qry_type in ["week","weekly"]:
ads_analytics_data["week"] = week_number
elif qry_type in ["month","monthly"]:
ads_analytics_data["month"] = startDate.month
elif qry_type in ["day","daily"]:
#ads_analytics_data["day_name"] = startDate.strftime('%A')
ads_analytics_data["week"] = week_number
#Be sure to close the report.
report_container.close()
return ads_analytics_data
except:
print("\nDOWNLOAD_ADS_REPORT : processing Failed : ", sys.exc_info())
from the log, we can only tell that the access token is expired. we do not know how do you setup your authorization_data. so can not tell what is wrong. I tested the sample and it works with both production and sandbox env. Could you please try that?
FYI OAuthTokens has property access_token_received_datetime and access_token_expires_in_seconds. You may debug into it and see if it expires or not.
@qitia thank u alot for your responses, here is my code i setup the authorization_data from ms_auth function here is my code
from bingads.v13.reporting import *
import sys
from bingads.authorization import *
from bingads.service_client import ServiceClient
from urllib import parse
from datetime import datetime, timedelta
from bingads.service_client import ServiceClient
from bingads.v13 import *
from bingads.v13.reporting import *
from suds import WebFault
from suds.client import Client
def ms_auth(refresh_token,client_id,client_secrect,developer_token):
try:
authorization_data=AuthorizationData(
account_id=None,
customer_id=None,
developer_token=developer_token,
authentication=None,
)
authentication=OAuthDesktopMobileAuthCodeGrant(
client_id=client_id,
env='production'
)
authentication.state='bld@bingads_amp'
authentication.client_secret=client_secrect
# Assign this authentication instance to the authorization_data.
authorization_data.authentication=authentication
authorization_data.authentication.request_oauth_tokens_by_refresh_token(refresh_token)
print("MS_AUTHENTICATION: authentication process finished successfully\n")
return authorization_data
except:
print("\nMS_AUTHENTICATION: authentication process Failed : ",sys.exc_info())
client_id = "**************************"
client_secret = "**************************"
developer_token = "***********************"
access_secret = "********************************"
refresh_token = "*****************************************"
authorization_data = ms_auth(refresh_token,client_id,client_secret,developer_token)
# You must provide credentials in auth_helper.py.
# The report file extension type.
REPORT_FILE_FORMAT='Csv'
# The directory for the report files.
FILE_DIRECTORY='c:/reports/'
# The name of the report download file.
RESULT_FILE_NAME='result.' + REPORT_FILE_FORMAT.lower()
# The maximum amount of time (in milliseconds) that you want to wait for the report download.
TIMEOUT_IN_MILLISECONDS=3600000
def main(authorization_data):
try:
# You can submit one of the example reports, or build your own.
report_request=get_report_request(authorization_data.account_id)
reporting_download_parameters = ReportingDownloadParameters(
report_request=report_request,
result_file_directory = FILE_DIRECTORY,
result_file_name = RESULT_FILE_NAME,
overwrite_result_file = True, # Set this value true if you want to overwrite the same file.
timeout_in_milliseconds=TIMEOUT_IN_MILLISECONDS # You may optionally cancel the download after a specified time interval.
)
#Option A - Background Completion with ReportingServiceManager
#You can submit a download request and the ReportingServiceManager will automatically
#return results. The ReportingServiceManager abstracts the details of checking for result file
#completion, and you don't have to write any code for results polling.
#output_status_message("-----\nAwaiting Background Completion...")
#background_completion(reporting_download_parameters)
#Option B - Submit and Download with ReportingServiceManager
#Submit the download request and then use the ReportingDownloadOperation result to
#track status yourself using ReportingServiceManager.get_status().
#output_status_message("-----\nAwaiting Submit and Download...")
#submit_and_download(report_request)
#Option C - Download Results with ReportingServiceManager
#If for any reason you have to resume from a previous application state,
#you can use an existing download request identifier and use it
#to download the result file.
#For example you might have previously retrieved a request ID using submit_download.
#reporting_operation=reporting_service_manager.submit_download(report_request)
#request_id=reporting_operation.request_id
#Given the request ID above, you can resume the workflow and download the report.
#The report request identifier is valid for two days.
#If you do not download the report within two days, you must request the report again.
#output_status_message("-----\nAwaiting Download Results...")
#download_results(request_id, authorization_data)
#Option D - Download the report in memory with ReportingServiceManager.download_report
#The download_report helper function downloads the report and summarizes results.
output_status_message("-----\nAwaiting download_report...")
download_report(reporting_download_parameters)
except WebFault as ex:
output_webfault_errors(ex)
except Exception as ex:
output_status_message(ex)
def background_completion(reporting_download_parameters):
""" You can submit a download request and the ReportingServiceManager will automatically
return results. The ReportingServiceManager abstracts the details of checking for result file
completion, and you don't have to write any code for results polling. """
global reporting_service_manager
result_file_path = reporting_service_manager.download_file(reporting_download_parameters)
output_status_message("Download result file: {0}".format(result_file_path))
def submit_and_download(report_request):
""" Submit the download request and then use the ReportingDownloadOperation result to
track status until the report is complete e.g. either using
ReportingDownloadOperation.track() or ReportingDownloadOperation.get_status(). """
global reporting_service_manager
reporting_download_operation = reporting_service_manager.submit_download(report_request)
# You may optionally cancel the track() operation after a specified time interval.
reporting_operation_status = reporting_download_operation.track(timeout_in_milliseconds=TIMEOUT_IN_MILLISECONDS)
# You can use ReportingDownloadOperation.track() to poll until complete as shown above,
# or use custom polling logic with get_status() as shown below.
#for i in range(10):
# time.sleep(reporting_service_manager.poll_interval_in_milliseconds / 1000.0)
# download_status = reporting_download_operation.get_status()
# if download_status.status == 'Success':
# break
result_file_path = reporting_download_operation.download_result_file(
result_file_directory = FILE_DIRECTORY,
result_file_name = RESULT_FILE_NAME,
decompress = True,
overwrite = True, # Set this value true if you want to overwrite the same file.
timeout_in_milliseconds=TIMEOUT_IN_MILLISECONDS # You may optionally cancel the download after a specified time interval.
)
output_status_message("Download result file: {0}".format(result_file_path))
def download_results(request_id, authorization_data):
""" If for any reason you have to resume from a previous application state,
you can use an existing download request identifier and use it
to download the result file. Use ReportingDownloadOperation.track() to indicate that the application
should wait to ensure that the download status is completed. """
reporting_download_operation = ReportingDownloadOperation(
request_id = request_id,
authorization_data=authorization_data,
poll_interval_in_milliseconds=1000,
environment='production',
)
# Use track() to indicate that the application should wait to ensure that
# the download status is completed.
# You may optionally cancel the track() operation after a specified time interval.
reporting_operation_status = reporting_download_operation.track(timeout_in_milliseconds=TIMEOUT_IN_MILLISECONDS)
result_file_path = reporting_download_operation.download_result_file(
result_file_directory = FILE_DIRECTORY,
result_file_name = RESULT_FILE_NAME,
decompress = True,
overwrite = True, # Set this value true if you want to overwrite the same file.
timeout_in_milliseconds=TIMEOUT_IN_MILLISECONDS # You may optionally cancel the download after a specified time interval.
)
output_status_message("Download result file: {0}".format(result_file_path))
output_status_message("Status: {0}".format(reporting_operation_status.status))
def download_report(reporting_download_parameters):
""" You can get a Report object by submitting a new download request via ReportingServiceManager.
Although in this case you will not work directly with the file, under the covers a request is
submitted to the Reporting service and the report file is downloaded to a local directory. """
global reporting_service_manager
report_container = reporting_service_manager.download_report(reporting_download_parameters)
#Otherwise if you already have a report file that was downloaded via the API,
#you can get a Report object via the ReportFileReader.
# report_file_reader = ReportFileReader(
# file_path = reporting_download_parameters.result_file_directory + reporting_download_parameters.result_file_name,
# format = reporting_download_parameters.report_request.Format)
# report_container = report_file_reader.get_report()
if(report_container == None):
output_status_message("There is no report data for the submitted report request parameters.")
sys.exit(0)
#Once you have a Report object via either workflow above, you can access the metadata and report records.
#Output the report metadata
record_count = report_container.record_count
output_status_message("ReportName: {0}".format(report_container.report_name))
output_status_message("ReportTimeStart: {0}".format(report_container.report_time_start))
output_status_message("ReportTimeEnd: {0}".format(report_container.report_time_end))
output_status_message("LastCompletedAvailableDate: {0}".format(report_container.last_completed_available_date))
output_status_message("ReportAggregation: {0}".format(report_container.report_aggregation))
output_status_message("ReportColumns: {0}".format("; ".join(str(column) for column in report_container.report_columns)))
output_status_message("ReportRecordCount: {0}".format(record_count))
#Analyze and output performance statistics
if "Impressions" in report_container.report_columns and \
"Clicks" in report_container.report_columns and \
"DeviceType" in report_container.report_columns and \
"Network" in report_container.report_columns:
report_record_iterable = report_container.report_records
total_impressions = 0
total_clicks = 0
distinct_devices = set()
distinct_networks = set()
for record in report_record_iterable:
total_impressions += record.int_value("Impressions")
total_clicks += record.int_value("Clicks")
distinct_devices.add(record.value("DeviceType"))
distinct_networks.add(record.value("Network"))
output_status_message("Total Impressions: {0}".format(total_impressions))
output_status_message("Total Clicks: {0}".format(total_clicks))
output_status_message("Average Impressions: {0}".format(total_impressions * 1.0 / record_count))
output_status_message("Average Clicks: {0}".format(total_clicks * 1.0 / record_count))
output_status_message("Distinct Devices: {0}".format("; ".join(str(device) for device in distinct_devices)))
output_status_message("Distinct Networks: {0}".format("; ".join(str(network) for network in distinct_networks)))
#Be sure to close the report.
report_container.close()
def get_report_request(account_id):
"""
Use a sample report request or build your own.
"""
aggregation = 'Daily'
exclude_column_headers=False
exclude_report_footer=False
exclude_report_header=False
time=reporting_service.factory.create('ReportTime')
# You can either use a custom date range or predefined time.
time.PredefinedTime='Yesterday'
time.ReportTimeZone='PacificTimeUSCanadaTijuana'
return_only_complete_data=False
#BudgetSummaryReportRequest does not contain a definition for Aggregation.
budget_summary_report_request=get_budget_summary_report_request(
account_id=account_id,
exclude_column_headers=exclude_column_headers,
exclude_report_footer=exclude_report_footer,
exclude_report_header=exclude_report_header,
report_file_format=REPORT_FILE_FORMAT,
return_only_complete_data=return_only_complete_data,
time=time)
campaign_performance_report_request=get_campaign_performance_report_request(
account_id=account_id,
aggregation=aggregation,
exclude_column_headers=exclude_column_headers,
exclude_report_footer=exclude_report_footer,
exclude_report_header=exclude_report_header,
report_file_format=REPORT_FILE_FORMAT,
return_only_complete_data=return_only_complete_data,
time=time)
keyword_performance_report_request=get_keyword_performance_report_request(
account_id=account_id,
aggregation=aggregation,
exclude_column_headers=exclude_column_headers,
exclude_report_footer=exclude_report_footer,
exclude_report_header=exclude_report_header,
report_file_format=REPORT_FILE_FORMAT,
return_only_complete_data=return_only_complete_data,
time=time)
user_location_performance_report_request=get_user_location_performance_report_request(
account_id=account_id,
aggregation=aggregation,
exclude_column_headers=exclude_column_headers,
exclude_report_footer=exclude_report_footer,
exclude_report_header=exclude_report_header,
report_file_format=REPORT_FILE_FORMAT,
return_only_complete_data=return_only_complete_data,
time=time)
return campaign_performance_report_request
def get_budget_summary_report_request(
account_id,
exclude_column_headers,
exclude_report_footer,
exclude_report_header,
report_file_format,
return_only_complete_data,
time):
report_request=reporting_service.factory.create('BudgetSummaryReportRequest')
report_request.ExcludeColumnHeaders=exclude_column_headers
report_request.ExcludeReportFooter=exclude_report_footer
report_request.ExcludeReportHeader=exclude_report_header
report_request.Format=report_file_format
report_request.ReturnOnlyCompleteData=return_only_complete_data
report_request.Time=time
report_request.ReportName="My Budget Summary Report"
scope=reporting_service.factory.create('AccountThroughCampaignReportScope')
scope.AccountIds={'long': [account_id] }
scope.Campaigns=None
report_request.Scope=scope
report_columns=reporting_service.factory.create('ArrayOfBudgetSummaryReportColumn')
report_columns.BudgetSummaryReportColumn.append([
'AccountName',
'AccountNumber',
'AccountId',
'CampaignName',
'CampaignId',
'Date',
'CurrencyCode',
'MonthlyBudget',
'DailySpend',
'MonthToDateSpend'
])
report_request.Columns=report_columns
return report_request
def get_campaign_performance_report_request(
account_id,
aggregation,
exclude_column_headers,
exclude_report_footer,
exclude_report_header,
report_file_format,
return_only_complete_data,
time):
report_request=reporting_service.factory.create('CampaignPerformanceReportRequest')
report_request.Aggregation=aggregation
report_request.ExcludeColumnHeaders=exclude_column_headers
report_request.ExcludeReportFooter=exclude_report_footer
report_request.ExcludeReportHeader=exclude_report_header
report_request.Format=report_file_format
report_request.ReturnOnlyCompleteData=return_only_complete_data
report_request.Time=time
report_request.ReportName="My Campaign Performance Report"
scope=reporting_service.factory.create('AccountThroughCampaignReportScope')
scope.AccountIds={'long': [account_id] }
scope.Campaigns=None
report_request.Scope=scope
report_columns=reporting_service.factory.create('ArrayOfCampaignPerformanceReportColumn')
report_columns.CampaignPerformanceReportColumn.append([
'TimePeriod',
'CampaignId',
'CampaignName',
'DeviceType',
'Network',
'Impressions',
'Clicks',
'Spend'
])
report_request.Columns=report_columns
return report_request
def get_keyword_performance_report_request(
account_id,
aggregation,
exclude_column_headers,
exclude_report_footer,
exclude_report_header,
report_file_format,
return_only_complete_data,
time):
report_request=reporting_service.factory.create('KeywordPerformanceReportRequest')
report_request.Aggregation=aggregation
report_request.ExcludeColumnHeaders=exclude_column_headers
report_request.ExcludeReportFooter=exclude_report_footer
report_request.ExcludeReportHeader=exclude_report_header
report_request.Format=report_file_format
report_request.ReturnOnlyCompleteData=return_only_complete_data
report_request.Time=time
report_request.ReportName="My Keyword Performance Report"
scope=reporting_service.factory.create('AccountThroughAdGroupReportScope')
scope.AccountIds={'long': [account_id] }
scope.Campaigns=None
scope.AdGroups=None
report_request.Scope=scope
report_columns=reporting_service.factory.create('ArrayOfKeywordPerformanceReportColumn')
report_columns.KeywordPerformanceReportColumn.append([
'TimePeriod',
'AccountId',
'CampaignId',
'Keyword',
'KeywordId',
'DeviceType',
'Network',
'Impressions',
'Clicks',
'Spend',
'BidMatchType',
'Ctr',
'AverageCpc',
'QualityScore'
])
report_request.Columns=report_columns
return report_request
def get_user_location_performance_report_request(
account_id,
aggregation,
exclude_column_headers,
exclude_report_footer,
exclude_report_header,
report_file_format,
return_only_complete_data,
time):
report_request=reporting_service.factory.create('UserLocationPerformanceReportRequest')
report_request.Aggregation=aggregation
report_request.ExcludeColumnHeaders=exclude_column_headers
report_request.ExcludeReportFooter=exclude_report_footer
report_request.ExcludeReportHeader=exclude_report_header
report_request.Format=report_file_format
report_request.ReturnOnlyCompleteData=return_only_complete_data
report_request.Time=time
report_request.ReportName="My User Location Performance Report"
scope=reporting_service.factory.create('AccountThroughAdGroupReportScope')
scope.AccountIds={'long': [account_id] }
scope.Campaigns=None
scope.AdGroups=None
report_request.Scope=scope
report_columns=reporting_service.factory.create('ArrayOfUserLocationPerformanceReportColumn')
report_columns.UserLocationPerformanceReportColumn.append([
'TimePeriod',
'AccountId',
'AccountName',
'CampaignId',
'AdGroupId',
'LocationId',
'Country',
'Clicks',
'Impressions',
'DeviceType',
'Network',
'Ctr',
'AverageCpc',
'Spend',
])
report_request.Columns=report_columns
return report_request
# Main execution
if __name__ == '__main__':
print("Loading the web service client proxies...")
authorization_data=AuthorizationData(
account_id=None,
customer_id=None,
developer_token='****************',
authentication=None,
)
reporting_service_manager=ReportingServiceManager(
authorization_data=authorization_data,
poll_interval_in_milliseconds=5000,
environment='production',
)
# In addition to ReportingServiceManager, you will need a reporting ServiceClient
# to build the ReportRequest.
reporting_service=ServiceClient(
service='ReportingService',
version=13,
authorization_data=authorization_data,
environment='production',
)
main(authorization_data)
do i pass authorization_data correctly ? "NoneType' object has no attribute 'enrich_headers'" i get this error
hi @FakerBZD from you code I see two issues: 1, in the main method you create the authorization_data again without authentication, you initiate ServiceClient with this auth_data, it is wrong 2, in the ms_auth method, you did not specify accountid and customerid, which are expected.
Could you please try again after fix them?
hi, @qitia thank you for help 1- the authentication take object OAuthDesktopMobileAuthCodeGrant ?
authorization_data=AuthorizationData(
account_id='*******',
customer_id='************',
developer_token='*************',
authentication=None,
)
authentication=OAuthDesktopMobileAuthCodeGrant(
client_id=client_id,
env='production'
)
authentication.state='bld@bingads_amp'
authentication.client_secret=client_secrect
# Assign this authentication instance to the authorization_data.
authorization_data.authentication=authentication
authorization_data.authentication.request_oauth_tokens_by_refresh_token(refresh_token)
how i can iniate ServiceClient ? sorry for the silly questions i started the project with soap requests so i really still don"t understand the sdk
update : i get this error
MS_AUTHENTICATION: authentication process finished successfully
> Loading the web service client proxies...
> -----
> Awaiting download_report...
> Web service reported a SOAP processing fault using an unexpected HTTP status code 200. Reporting as an internal server error.
> <suds.sax.document.Document object at 0x00000229F8A1BF40>
> ErrorCode: AccountNotAuthorized
> Code: 2003
> Details:
> Message: The specified report request contains at least one account which you have insufficient privileges to access. Please submit a report request for accounts that you are authorized to access.
> i get this error im getting account id and customer_id with getuser soap request
did you fix the first issue? in your code, authorization_data you created in your main method never get authenticate...
if you already fix this issue? are you getting "The specified report request contains at least one account which you have insufficient privileges to access. Please submit a report request for accounts that you are authorized to access." now? if yes please reach out the support team to verify you have the right access to that account.
@qitia , yes im getting "The specified report request contains at least one account which you have insufficient privileges to access. Please submit a report request for accounts that you are authorized to access" now thanks alot for the help i will reach the support team
so I close this issue. feel free to reopen in case of further question.
Hi Team, we are trying to get ad spend reports , we are able to get campaings ids names .... with soap requests but we get invalid client data when we are trying to sent requests to reporting api we try to relay on pyhton sdk for getting reports using this tutorial we get
the user grant
msads.mange
scope in the authentication consent screen thank you