代码之家  ›  专栏  ›  技术社区  ›  asfsadf

亚马逊产品API-C#中是否有任何有效的、最新的示例?

  •  8
  • asfsadf  · 技术社区  · 15 年前

    我必须已经运行了10个不同的样本C#项目已经过时,不再工作。

    我所追求的只是一种基于ISBN或书名来获取书籍信息的方法。

    亚马逊网站是一个绝对悲惨的泥沼。

    更新:

    我设法利用 this 作为起点,并已成功完成基本请求。我将继续寻找其他最新的资源,这些资源可能会进入其他一些详细的场景。

    4 回复  |  直到 9 年前
        1
  •  2
  •   Daniel    15 年前

    不久前,我编写了一个客户端库,用于与Amazon的ECS(A2S)服务通信。似乎亚马逊讨厌他们的开发人员,并不断更改他们的服务名称和框架。好吧,我的客户现在完全破产了,因为 Recent API Changes .

    你最好看看他们的样品 here .

    祝你好运。他们的API是巨大的和过时的经验,我有,但那是两年前。我的印象是,他们真正迎合的是开发人员的企业服务,而不是免费的A2S。

        2
  •  3
  •   Anton    15 年前

    NET的SprightlySoft AWS组件允许您与包括产品广告API在内的所有Amazon服务进行交互。下面是一些查找ISBN的示例代码。免费获取组件 http://sprightlysoft.com/ .

    //Product Advertising API, ItemLookup: http://docs.amazonwebservices.com/AWSECommerceService/2010-10-01/DG/ItemLookup.html
    
    SprightlySoftAWS.REST MyREST = new SprightlySoftAWS.REST();
    
    String RequestURL;
    RequestURL = "https://ecs.amazonaws.com/onca/xml?Service=AWSECommerceService&Operation=ItemLookup&Version=2010-10-01";
    RequestURL += "&AWSAccessKeyId=" + System.Uri.EscapeDataString(AWSAccessKeyId) + "&SignatureVersion=2&SignatureMethod=HmacSHA256&Timestamp=" + Uri.EscapeDataString(DateTime.UtcNow.ToString("yyyy-MM-dd\\THH:mm:ss.fff\\Z"));
    RequestURL += "&ItemId=9781904233657";
    RequestURL += "&IdType=ISBN";
    RequestURL += "&SearchIndex=Books";
    
    String RequestMethod;
    RequestMethod = "GET";
    
    String SignatureValue;
    SignatureValue = MyREST.GetSignatureVersion2Value(RequestURL, RequestMethod, "", AWSSecretAccessKey);
    
    RequestURL += "&Signature=" + System.Uri.EscapeDataString(SignatureValue);
    
    Boolean RetBool;
    RetBool = MyREST.MakeRequest(RequestURL, RequestMethod, null);
    
    System.Diagnostics.Debug.Print("");
    System.Diagnostics.Debug.Print(MyREST.LogData);
    System.Diagnostics.Debug.Print("");
    
    String ResponseMessage = "";
    
    if (RetBool == true)
    {
        System.Xml.XmlDocument MyXmlDocument;
        System.Xml.XmlNamespaceManager MyXmlNamespaceManager;
        System.Xml.XmlNode MyXmlNode;
        System.Xml.XmlNodeList MyXmlNodeList;
    
        MyXmlDocument = new System.Xml.XmlDocument();
        MyXmlDocument.LoadXml(MyREST.ResponseString);
    
        MyXmlNamespaceManager = new System.Xml.XmlNamespaceManager(MyXmlDocument.NameTable);
        MyXmlNamespaceManager.AddNamespace("amz", "http://webservices.amazon.com/AWSECommerceService/2010-10-01");
    
        MyXmlNodeList = MyXmlDocument.SelectNodes("amz:ItemLookupResponse/amz:Items/amz:Item", MyXmlNamespaceManager);
    
        if (MyXmlNodeList.Count == 0)
        {
            ResponseMessage = "No items found.";
        }
        else
        {
            foreach (System.Xml.XmlNode ItemXmlNode in MyXmlNodeList)
            {
                MyXmlNode = ItemXmlNode.SelectSingleNode("amz:ItemAttributes/amz:Title", MyXmlNamespaceManager);
                ResponseMessage += "Title = " + MyXmlNode.InnerText;
    
                ResponseMessage += Environment.NewLine;
            }
        }
    
        MessageBox.Show(ResponseMessage);
    }
    else
    {
        ResponseMessage = MyREST.ResponseStringFormatted;
    
        MessageBox.Show(ResponseMessage);
    }
    
        3
  •  1
  •   takrl cck    15 年前

    我也一直在努力解决这个问题(我也在学习阶段)。

    我发现最有效的方法是使用REST api,然后使用Linq to XML将结果解析为可以使用的自定义结果对象。请原谅长代码粘贴(不确定协议是否与此板上的代码一致),但我想你会想要全部的。其中大部分来自亚马逊自己的一个样本,但是这个网站没有组织起来,所以我很难再找到它。

    // custom class for result item
    public class AmazonBookSearchResult
    {
        public string ASIN;
        public string Author;
        public string Title;
        public Uri DetailPageURL;
        public Uri AllCustomerReviews;
    }
    
    // I call this with the search terms, returns an IEnumerable of results
    public class ItemLookup
    {
        private const string MY_AWS_ACCESS_KEY_ID = "YOUR KEY";
        private const string MY_AWS_SECRET_KEY = "YOUR KEY";
        private const string DESTINATION = "ecs.amazonaws.com";
    
        private const string NAMESPACE = "http://webservices.amazon.com/AWSECommerceService/2009-03-31";
    
        public static IEnumerable<AmazonBookSearchResult> AmazonItemLookup(string category, string browseNode, string keyWords)
        {
            SignedRequestHelper helper = new SignedRequestHelper(MY_AWS_ACCESS_KEY_ID, MY_AWS_SECRET_KEY, DESTINATION);
            String requestUrl;
    
            IDictionary<string, string> r1 = new Dictionary<string, String>();
            r1["Service"] = "AWSECommerceService";
            r1["Version"] = "2009-03-31";
            r1["Operation"] = "ItemSearch";
            r1["ResponseGroup"] = "ItemAttributes";
            r1["SearchIndex"] = category;
            r1["Keywords"] = keyWords;
    
            requestUrl = helper.Sign(r1);
            XmlDocument xmlDoc = sendRequest(requestUrl);
            XDocument doc = XDocument.Load(new XmlNodeReader(xmlDoc));
    
            XNamespace ns = "http://webservices.amazon.com/AWSECommerceService/2009-03-31";
            IEnumerable<AmazonBookSearchResult> result =
                from items in doc.Element(ns + "ItemSearchResponse").Elements(ns + "Items").Elements(ns + "Item")
                select new AmazonBookSearchResult
                {
                    ASIN = (string)items.Element(ns + "ASIN")
                };
    
            int count = doc.Element(ns + "ItemSearchResponse").Elements(ns + "Items").Elements(ns + "Item").Count();
    
            return result;
    
        } // end Lookup()
    
        // this is just taken from the amazon sample
        private static XmlDocument sendRequest(string url)
        {
            try
            {
                WebRequest request = HttpWebRequest.Create(url);
                WebResponse response = request.GetResponse();
                XmlDocument doc = new XmlDocument();
                doc.Load(response.GetResponseStream());
    
                XmlNodeList errorMessageNodes = doc.GetElementsByTagName("Message", NAMESPACE);
                if (errorMessageNodes != null && errorMessageNodes.Count > 0)
                {
                    String message = errorMessageNodes.Item(0).InnerText;
                    throw new Exception("Error " + message);
                }
    
                return doc;
            }
            catch (Exception e)
            {
                System.Console.WriteLine("Caught Exception: " + e.Message);
                System.Console.WriteLine("Stack Trace: " + e.StackTrace);
            }
    
            return null;
        }// end FetchTitle()
    }
    
    class SignedRequestHelper
    {
        private string endPoint;
        private string akid;
        private byte[] secret;
        private HMAC signer;
    
        private const string REQUEST_URI = "/onca/xml";
        private const string REQUEST_METHOD = "GET";
    
        /*
         * Use this constructor to create the object. The AWS credentials are available on
         * http://aws.amazon.com
         *
         * The destination is the service end-point for your application:
         *  US: ecs.amazonaws.com
         *  JP: ecs.amazonaws.jp
         *  UK: ecs.amazonaws.co.uk
         *  DE: ecs.amazonaws.de
         *  FR: ecs.amazonaws.fr
         *  CA: ecs.amazonaws.ca
         */
        public SignedRequestHelper(string awsAccessKeyId, string awsSecretKey, string destination)
        {
            this.endPoint = destination.ToLower();
            this.akid = awsAccessKeyId;
            this.secret = Encoding.UTF8.GetBytes(awsSecretKey);
            this.signer = new HMACSHA256(this.secret);
        }
    
        /*
         * Sign a request in the form of a Dictionary of name-value pairs.
         *
         * This method returns a complete URL to use. Modifying the returned URL
         * in any way invalidates the signature and Amazon will reject the requests.
         */
        public string Sign(IDictionary<string, string> request)
        {
            // Use a SortedDictionary to get the parameters in naturual byte order, as
            // required by AWS.
            ParamComparer pc = new ParamComparer();
            SortedDictionary<string, string> sortedMap = new SortedDictionary<string, string>(request, pc);
    
            // Add the AWSAccessKeyId and Timestamp to the requests.
            sortedMap["AWSAccessKeyId"] = this.akid;
            sortedMap["Timestamp"] = this.GetTimestamp();
    
            // Get the canonical query string
            string canonicalQS = this.ConstructCanonicalQueryString(sortedMap);
    
            // Derive the bytes needs to be signed.
            StringBuilder builder = new StringBuilder();
            builder.Append(REQUEST_METHOD)
                .Append("\n")
                .Append(this.endPoint)
                .Append("\n")
                .Append(REQUEST_URI)
                .Append("\n")
                .Append(canonicalQS);
    
            string stringToSign = builder.ToString();
            byte[] toSign = Encoding.UTF8.GetBytes(stringToSign);
    
            // Compute the signature and convert to Base64.
            byte[] sigBytes = signer.ComputeHash(toSign);
            string signature = Convert.ToBase64String(sigBytes);
    
            // now construct the complete URL and return to caller.
            StringBuilder qsBuilder = new StringBuilder();
            qsBuilder.Append("http://")
                .Append(this.endPoint)
                .Append(REQUEST_URI)
                .Append("?")
                .Append(canonicalQS)
                .Append("&Signature=")
                .Append(this.PercentEncodeRfc3986(signature));
    
            return qsBuilder.ToString();
        }
    
        /*
         * Sign a request in the form of a query string.
         *
         * This method returns a complete URL to use. Modifying the returned URL
         * in any way invalidates the signature and Amazon will reject the requests.
         */
        public string Sign(string queryString)
        {
            IDictionary<string, string> request = this.CreateDictionary(queryString);
            return this.Sign(request);
        }
    
        /*
         * Current time in IS0 8601 format as required by Amazon
         */
        private string GetTimestamp()
        {
            DateTime currentTime = DateTime.UtcNow;
            string timestamp = currentTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
            return timestamp;
        }
    
        /*
         * Percent-encode (URL Encode) according to RFC 3986 as required by Amazon.
         *
         * This is necessary because .NET's HttpUtility.UrlEncode does not encode
         * according to the above standard. Also, .NET returns lower-case encoding
         * by default and Amazon requires upper-case encoding.
         */
        private string PercentEncodeRfc3986(string str)
        {
            str = HttpUtility.UrlEncode(str, System.Text.Encoding.UTF8);
            str = str.Replace("'", "%27").Replace("(", "%28").Replace(")", "%29").Replace("*", "%2A").Replace("!", "%21").Replace("%7e", "~").Replace("+", "%20");
    
            StringBuilder sbuilder = new StringBuilder(str);
            for (int i = 0; i < sbuilder.Length; i++)
            {
                if (sbuilder[i] == '%')
                {
                    if (Char.IsLetter(sbuilder[i + 1]) || Char.IsLetter(sbuilder[i + 2]))
                    {
                        sbuilder[i + 1] = Char.ToUpper(sbuilder[i + 1]);
                        sbuilder[i + 2] = Char.ToUpper(sbuilder[i + 2]);
                    }
                }
            }
            return sbuilder.ToString();
        }
    
        /*
         * Convert a query string to corresponding dictionary of name-value pairs.
         */
        private IDictionary<string, string> CreateDictionary(string queryString)
        {
            Dictionary<string, string> map = new Dictionary<string, string>();
    
            string[] requestParams = queryString.Split('&');
    
            for (int i = 0; i < requestParams.Length; i++)
            {
                if (requestParams[i].Length < 1)
                {
                    continue;
                }
    
                char[] sep = { '=' };
                string[] param = requestParams[i].Split(sep, 2);
                for (int j = 0; j < param.Length; j++)
                {
                    param[j] = HttpUtility.UrlDecode(param[j], System.Text.Encoding.UTF8);
                }
                switch (param.Length)
                {
                    case 1:
                        {
                            if (requestParams[i].Length >= 1)
                            {
                                if (requestParams[i].ToCharArray()[0] == '=')
                                {
                                    map[""] = param[0];
                                }
                                else
                                {
                                    map[param[0]] = "";
                                }
                            }
                            break;
                        }
                    case 2:
                        {
                            if (!string.IsNullOrEmpty(param[0]))
                            {
                                map[param[0]] = param[1];
                            }
                        }
                        break;
                }
            }
    
            return map;
        }
    
        /*
         * Consttuct the canonical query string from the sorted parameter map.
         */
        private string ConstructCanonicalQueryString(SortedDictionary<string, string> sortedParamMap)
        {
            StringBuilder builder = new StringBuilder();
    
            if (sortedParamMap.Count == 0)
            {
                builder.Append("");
                return builder.ToString();
            }
    
            foreach (KeyValuePair<string, string> kvp in sortedParamMap)
            {
                builder.Append(this.PercentEncodeRfc3986(kvp.Key));
                builder.Append("=");
                builder.Append(this.PercentEncodeRfc3986(kvp.Value));
                builder.Append("&");
            }
            string canonicalString = builder.ToString();
            canonicalString = canonicalString.Substring(0, canonicalString.Length - 1);
            return canonicalString;
        }
    }
    
    /*
     * To help the SortedDictionary order the name-value pairs in the correct way.
     */
    class ParamComparer : IComparer<string>
    {
        public int Compare(string p1, string p2)
        {
            return string.CompareOrdinal(p1, p2);
        }
    }
    
        4
  •  0
  •   Sepster    14 年前

    你可以从亚马逊下载这个例子 Product Advertising API Signed Requests Sample Code - C# SOAP WCF 4.0

    如果您使用SOAP(在本例中),获得所需的信息将比使用REST简单得多。

    我不认为在这种情况下使用REST比使用SOAP调用更简单,后者在C中返回一个格式良好的对象,在该对象中,您可以获得所需的有关产品的所有信息,而无需所有额外的编码。我想现在每个人都在使用REST是因为它很时髦,我只在更容易集成的时候使用它。在Amazon产品广告API的情况下,我宁愿使用SOAP API。