amazon_advertising开发:下载报告

在亚马逊官方文档中,可以看到下图所示的三种广告类型
在这里插入图片描述
这里我使用的时products广告,展开任意一种广告,可以看到reference中有report选项,下载报告的入口就在这里,如下图:
在这里插入图片描述
这里需要注意一点区别,display中的report有如下三个方法,分别是创建报告,查询报告状态,下载报告,如下图:
在这里插入图片描述
而products则只有两个,如下图,第三步下载报告省略了,并不是没有,做法跟display中的第三步一样。我真的好像啐写文档的人一脸。。。
在这里插入图片描述
下载报告需要完成如下三个步骤:

  1. 【post】/v2/sp/{recordType}/report,创建报告;
  2. 【get】/v2/reports/{reportId},检查报告的生成状态;
  3. 【get】/v2/reports/{reportId}/download,下载报告。
    下面详细解释。

步骤一
post请求必须包含header参数、body参数和beared auth认证。其中header跟beared auth认证基本是每次向亚马逊发送请求都必须用到的(最初获取token和步骤三重定向是不用,这个在步骤三时有个坑,在步骤三具体讲)。其中:

  1. clientId 是一开始请求 access_token 时就用的 clientId;
  2. scope 指的是 profileId,你拿到 access_token 后要先 get profiles(文档最后一行),会获取到一堆 profileId,profiles 的作用官方文档里写得很清楚,要想得到 campaigns 和 report 等数据,这个必须要有;
  3. Bearer auth 是前面获取的 access_token(这个参数文档里是写在沙箱环境那一块了,请移步去看,有时候遇到一些莫名其妙的访问不成功的错误就去看看,可能是漏掉了什么参数)。

这些请求头信息可以写成一个公共头,每次发起请求时直接调用就可以了。body是请求的报告中应包含的信息,官方文档对每个参数都有详细解释,请移步文档查看。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
请求结果:
在这里插入图片描述
步骤二
header参数跟认证与步骤一一样,没有body。发送get请求后可以得到报告的生成状态:
在这里插入图片描述
请求结果:
在这里插入图片描述
其实参数跟步骤一差不多,主要是这个“status”,如果为success就可以执行第三步下载报告了。

步骤三
header参数跟认证与步骤二一样,url使用步骤二返回的location即可,或者自己按照文档拼接也可。
在这里插入图片描述
请求结果:
在这里插入图片描述
报错了:

Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter, Signature query string parameter or the Authorization header should be specified

文档上说这个请求返回的是一个307重定向:

Gets a 307 Temporary Redirect response that includes a location header with the value set to an AWS S3 path where the report is located. The path expires after 30 seconds. If the path expires before the report is downloaded, a new report request must be created.

成功之后的响应值就是headers头中的location参数:
在这里插入图片描述
但这里的报错信息大致意思是:

这里的认证信息是多余的。

去掉认证访问的话又报错:

401 Unauthorized,没有认证。

之所以出现这样的问题是因为我在get的请求头中没有关闭自动跳转重定向。
http的get方法遇到返回的是307重定向默认是直接跳转的,跳转的时候会带上首次请求时的请求头信息,这就导致了此处的问题:带了认证说认证多余,不带认证又说你没有认证。

解决办法就是在get方法中关闭自动跳转,比如:

/***************************************************************
* 下面设置HttpWebRequest的相关属性
* ************************************************************/
request = (HttpWebRequest)WebRequest.Create(url);
request.UserAgent = USER_AGENT;
request.Method = "GET";
request.ContentType = "application/json";
request.AllowAutoRedirect = false;	// 关闭自动跳转
if (header != null)
    request.Headers = header;

2021.1.14:
补充:

  1. 需要注意的是,申请报告后如果立即查看报告状态大概率是失败的,会提示报告已提交正在生成。即便等待个二三十秒也不一定可以。因为我是把下载报告的操作放到window服务中执行,所以就把创建报告跟下载报告分开进行了。先创建报告,并把返回的reportId保存到数据库,隔几个小时再下载。
  2. 如果在今天刚开始的时候就创建报告,也会返回reportId,由于这一天还没过完,数据没统计出来,所以返回的报告是空的。
  3. 如果创建某一天的报告,针对一个profileId反复创建,每次都会返回不同的reportId,尽管最终拿到的内容都是一样的。既然reportId不唯一,就只能通过profileId和reportDate来判断本地数据库中是否已经有这个reportId了。

代码

获取报告的代码:

		#region 获取报告
        public void CreateReport(string state, string userName)
        {
            // 获取profileid
            ProfileDAL dalProfile = new ProfileDAL();
            var profileIds = dalProfile.GetProfileIds(userName);
            var reportDate = DateTime.Now.ToString("yyyyMMdd");
            var url = GetAdHost(state) + "/v2/sp/campaigns/report";

            // body参数
            Dictionary<string, string> dict = new Dictionary<string, string>();
            dict.Add("segment", "placement");
            dict.Add("reportDate", reportDate);
            dict.Add("metrics", Utils.ReadJsonToken(Token.CampaignMetrics));
            string body = JsonConvert.SerializeObject(dict);
            ReportDAL dalReport = new ReportDAL();
            foreach (var profileId in profileIds)
            {
                Report report = this.RequestReport(profileId, body, url, state, reportDate);
                if (report != null)
                {
                    ReportId rp = new ReportId()
                    {
                        RpId = report.ReportId,
                        ProfileId = profileId,
                        ReportDate = reportDate,
                        State = state,
                        UserName = userName
                    };
                    dalReport.SaveReportId(rp);
                }
            }
        }

        /// <summary>
        /// 创建报告
        /// </summary>
        /// <param name="profileId"></param>
        /// <param name="body">post请求的body参数</param>
        /// <param name="url"></param>
        /// <param name="state">国家代码</param>
        /// <param name="reportDate">请求的报告日期</param>
        /// <returns>amazon返回的报告内容,包括reportid,通过此id可下载报告</returns>
        private Report RequestReport(string profileId, string body, string url, string state, string reportDate)
        {
            WebHeaderCollection header = GetHeader(profileId);
            try
            {
                string resp = HttpService.Post(body, url, false, header, 5);
                if (resp == Unauthorized && this.GetTokens(state, null, true))
                {
                    return this.RequestReport(profileId, body, url, state, reportDate);
                }
                else
                {
                    return JsonConvert.DeserializeObject<Report>(resp);
                }
            }
            catch (Exception e)
            {
                Log.Error("Config", e.ToString());
                return null;
            }
        }

        public void DownReport(string userName)
        {
            ReportDAL dalReport = new ReportDAL();
            List<ReportId> reportIds = dalReport.GetReportId(userName);
            if (reportIds != null)
            {
                foreach (ReportId rp in reportIds)
                {
                    string result = string.Empty;
                    this.DownloadReport(rp.RpId, rp.State, rp.ProfileId, ref result);
                    if (!string.IsNullOrEmpty(result))
                    {
                        List<RpCampaign> campaigns = JsonConvert.DeserializeObject<List<RpCampaign>>(result);
                        foreach (var campaign in campaigns)
                        {
                            if (dalReport.Save(campaign, rp.ProfileId, rp.ReportDate, userName) > 0)
                            {
                                rp.Download = true;
                                rp.UserName = userName;
                                dalReport.UpdateReportId(rp);
                            }
                        }
                    }
                }
            }
        }
        private void DownloadReport(string reportId, string state, string profileId,ref string result)
        {
            if (!string.IsNullOrEmpty(reportId))
            {
                var url = GetAdHost(state) + "/v2/reports/" + reportId;

                WebHeaderCollection header = GetHeader(profileId);

                try
                {
                    var resp = HttpService.Get(url, header);
                    if (resp == Unauthorized && this.GetTokens(state, null, true))
                    {
                        this.DownloadReport(reportId, state, profileId, ref result);
                    }
                    else
                    {
                        Report report = JsonConvert.DeserializeObject<Report>(resp);
                        if (report.Status.Equals("SUCCESS"))
                        {
                            this.DownloadFile(report.Location, header, state, ref result);
                        }
                    }
                }
                catch (Exception e)
                {
                    Log.Error("Config", e.ToString());
                }
            }
        }

        private void DownloadFile(string url, WebHeaderCollection header, string state, ref string result)
        {
            try
            {
                var redirectUrl = HttpService.Get(url, header);
                if (redirectUrl == Unauthorized && this.GetTokens(state, null, true))
                {
                    this.DownloadFile(url, header, state, ref result);
                }
                else
                {
                    if (!string.IsNullOrEmpty(redirectUrl))
                    {
                        WebClient client = new WebClient();
                        byte[] data = client.DownloadData(redirectUrl);
                        byte[] newData = ZipHandler.GZipDeCompress(data);
                        result = Encoding.Default.GetString(newData);
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error("Config", e.ToString());
            }
        }
        #endregion

用到的其他方法:

		private string GetAdHost(string state)
        {
            var host = "";
            switch (state.ToUpper())
            {
                case "NA":
                    host = "https://advertising-api.amazon.com";
                    break;
                case "EU":
                    host = "https://advertising-api-eu.amazon.com";
                    break;
                case "FE":
                    host = "https://advertising-api-fe.amazon.com";
                    break;
                default:
                    host = "https://advertising-api.amazon.com";
                    break;
            }
            return host;
        }
        /// <summary>
        /// 获取公共请求头
        /// </summary>
        /// <returns></returns>
        private WebHeaderCollection GetHeader(string profileId = null)
        {
            var accessToken = Utils.ReadJsonToken(Token.AccessToken);
            WebHeaderCollection header = new WebHeaderCollection();
            header.Add(HttpRequestHeader.Authorization, "Bearer " + accessToken);
            header.Add("Amazon-Advertising-API-ClientId", this.ClientId);
            if (profileId != null)
                header.Add("Amazon-Advertising-API-Scope", profileId);
            return header;
        }

utils类:

using xxx.Common;
using xxx.DBUtility;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Data;
using System.IO;

namespace xxx.DAL.AD
{
    public class Utils
    {
        public static string ReadJsonToken(Token tokenName)
        {
            JObject jsonObject = null;
            StreamReader file = null;
            var path = GetJsonPath("token.json");
            try
            {
                file = File.OpenText(path);
                using (JsonTextReader reader = new JsonTextReader(file))
                {
                    jsonObject = (JObject)JToken.ReadFrom(reader);
                }
            }
            catch (Exception e)
            {
                Log.Error("ReadJsonToken", e.Message + "\r\n token文件不存在");
                return null;
            }
            finally
            {
                if (file != null)
                    file.Close();
            }

            if (jsonObject == null) return null;

            try
            {
                var token = "";
                switch (tokenName)
                {
                    case Token.RefreshToken:
                        token = jsonObject["refreshToken"].ToString();
                        break;
                    case Token.AccessToken:
                        token = jsonObject["accessToken"].ToString();
                        break;
                    case Token.Client:
                        token = jsonObject["client"].ToString();
                        break;
                    case Token.Secret:
                        token = jsonObject["secret"].ToString();
                        break;
                    case Token.RedirectUri:
                        token = jsonObject["redirectUri"].ToString();
                        break;
                    case Token.CampaignMetrics:
                        token = jsonObject["campaignMetrics"].ToString();
                        break;
                }
                return token;
            }
            catch (Exception e)
            {
                Log.Error("ReadJsonToken", e.Message + "\r\n token.json中不存在此tokenName:" + tokenName);
                return null;
            }
        }

        public static bool WriteTokenToJson(string refreshToken, string accessToken)
        {
            try
            {
                string path = GetJsonPath("token.json");
                string jsonString = File.ReadAllText(path, System.Text.Encoding.UTF8);//读取文件
                JObject jobject = JObject.Parse(jsonString);//解析成json
                jobject["accessToken"] = accessToken;//替换需要的文件
                jobject["refreshToken"] = refreshToken;
                string convertString = Convert.ToString(jobject);//将json转换为string
                File.WriteAllText(path, convertString, System.Text.Encoding.UTF8);//将内容写进jon文件中
                return true;
            }
            catch (Exception e)
            {
                Log.Error("WriteTokenToJson", e.Message);
                return false;
            }
        }
    }

    public enum Token
    {
        RefreshToken,
        AccessToken,
        Client,
        Secret,
        RedirectUri,
        CampaignMetrics
    }
}

get和post方法:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Threading;

namespace xxx.Common
{
    /// <summary>
    /// http连接基础类,负责底层的http通信
    /// </summary>
    public class HttpService
    {
        private static string USER_AGENT = string.Format("xxx/{2} ({0}) .net/{1}", Environment.OSVersion, Environment.Version, typeof(HttpService).Assembly.GetName().Version);

        public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            //直接确认,否则打不开    
            return true;
        }

        /// <summary>
        /// 处理http POST请求,返回数据
        /// </summary>
        /// <param name="json">query参数或body参数。注:若没有body参数,则可将query参数传入;若有body参数,则传入body参数,query参数接到url后面</param>
        /// <param name="url"></param>
        /// <param name="isXml"></param>
        /// <param name="header"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public static string Post(string json, string url, bool isXml, WebHeaderCollection header, int timeout)
        {
            System.GC.Collect();//垃圾回收,回收没有正常关闭的http连接

            string result = "";//返回结果

            HttpWebRequest request = null;
            HttpWebResponse response = null;
            Stream reqStream = null;

            try
            {
                //设置最大连接数
                ServicePointManager.DefaultConnectionLimit = 200;
                //设置https验证方式
                if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback =
                            new RemoteCertificateValidationCallback(CheckValidationResult);
                }

                /***************************************************************
                * 下面设置HttpWebRequest的相关属性
                * ************************************************************/
                request = (HttpWebRequest)WebRequest.Create(url);
                request.UserAgent = USER_AGENT;
                request.Method = "POST";
                request.Timeout = timeout * 1000;
                if (header != null)
                    request.Headers = header;
                //设置POST的数据类型和长度
                request.ContentType = isXml ? "application/x-www-form-urlencoded" : "application/json";
                byte[] data = System.Text.Encoding.UTF8.GetBytes(json);
                request.ContentLength = data.Length;

                //往服务器写入数据
                reqStream = request.GetRequestStream();
                reqStream.Write(data, 0, data.Length);
                reqStream.Close();

                //获取服务端返回
                response = (HttpWebResponse)request.GetResponse();

                //获取服务端返回数据
                StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                result = sr.ReadToEnd().Trim();
                sr.Close();
            }
            catch (ThreadAbortException e)
            {
                Log.Error("HttpService", "Thread - caught ThreadAbortException - resetting.");
                Log.Error("Exception message: {0}", e.Message);
                Thread.ResetAbort();
            }
            catch (WebException e)
            {
                Log.Error("HttpService", e.ToString());
                if (e.Status == WebExceptionStatus.ProtocolError)
                {
                    var code = ((HttpWebResponse)e.Response).StatusCode;
                    Log.Error("HttpService", "StatusCode : " + code + "\r\n StatusDetails : " + ((HttpWebResponse)e.Response).StatusDescription);
                    if (code == HttpStatusCode.Unauthorized)
                    {
                        return "Unauthorized";
                    }
                }
                throw new WebException(e.ToString());
            }
            catch (Exception e)
            {
                Log.Error("HttpService", e.ToString());
                throw new Exception(e.ToString());
            }
            finally
            {
                //关闭连接和流
                if (response != null)
                {
                    response.Close();
                }
                if (request != null)
                {
                    request.Abort();
                }
            }
            return result;
        }

        /// <summary>
        /// 处理http GET请求,返回数据
        /// </summary>
        /// <param name="url">请求的url地址</param>
        /// <returns>http GET成功后返回的数据,失败抛WebException异常</returns>
        public static string Get(string url, WebHeaderCollection header)
        {
            System.GC.Collect();
            string result = "";

            HttpWebRequest request = null;
            HttpWebResponse response = null;

            //请求url以获取数据
            try
            {
                //设置最大连接数
                ServicePointManager.DefaultConnectionLimit = 200;
                //设置https验证方式
                if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback =
                            new RemoteCertificateValidationCallback(CheckValidationResult);
                }

                /***************************************************************
                * 下面设置HttpWebRequest的相关属性
                * ************************************************************/
                request = (HttpWebRequest)WebRequest.Create(url);
                request.UserAgent = USER_AGENT;
                request.Method = "GET";
                request.ContentType = "application/json";
                request.AllowAutoRedirect = false;
                if (header != null)
                    request.Headers = header;

                //获取服务器返回
                response = (HttpWebResponse)request.GetResponse();
                if (response.StatusCode == HttpStatusCode.TemporaryRedirect)
                {
                    result = response.GetResponseHeader("Location");
                }
                else
                {
                    //获取HTTP返回数据
                    StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                    result = sr.ReadToEnd().Trim();
                    sr.Close();
                }
            }
            catch (ThreadAbortException e)
            {
                Log.Error("HttpService", "Thread - caught ThreadAbortException - resetting.");
                Log.Error("Exception message: {0}", e.Message);
                Thread.ResetAbort();
            }
            catch (WebException e)
            {
                Log.Error("HttpService", e.ToString());
                if (e.Status == WebExceptionStatus.ProtocolError)
                {
                    var code = ((HttpWebResponse)e.Response).StatusCode;
                    Log.Error("HttpService", "StatusCode : " + code + "\r\n StatusDetails : " + ((HttpWebResponse)e.Response).StatusDescription);
                    if (code == HttpStatusCode.Unauthorized)
                    {
                        return "Unauthorized";
                    }
                }
                throw new WebException(e.ToString());
            }
            catch (Exception e)
            {
                Log.Error("HttpService", e.ToString());
                throw new Exception(e.ToString());
            }
            finally
            {
                //关闭连接和流
                if (response != null)
                {
                    response.Close();
                }
                if (request != null)
                {
                    request.Abort();
                }
            }
            return result;
        }
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值