通过 Java/SOAP 的亚马逊产品广告 API

Posted

技术标签:

【中文标题】通过 Java/SOAP 的亚马逊产品广告 API【英文标题】:Amazon Product Advertising API through Java/SOAP 【发布时间】:2012-01-10 07:23:06 【问题描述】:

我一直在使用亚马逊的产品广告 API,但我无法获得通过并提供数据的请求。我一直在努力解决这个问题:http://docs.amazonwebservices.com/AWSECommerceService/2011-08-01/GSG/ 和这个:Amazon Product Advertising API signed request with Java

这是我的代码。我使用以下代码生成了 SOAP 绑定:http://docs.amazonwebservices.com/AWSECommerceService/2011-08-01/GSG/YourDevelopmentEnvironment.html#Java

在 Classpath 上,我只有:commons-codec.1.5.jar

import com.ECS.client.jax.AWSECommerceService;
import com.ECS.client.jax.AWSECommerceServicePortType;
import com.ECS.client.jax.Item;
import com.ECS.client.jax.ItemLookup;
import com.ECS.client.jax.ItemLookupRequest;
import com.ECS.client.jax.ItemLookupResponse;
import com.ECS.client.jax.ItemSearchResponse;
import com.ECS.client.jax.Items;

public class Client 

    public static void main(String[] args) 

        String secretKey = <my-secret-key>;
        String awsKey = <my-aws-key>;

        System.out.println("API Test started");

        AWSECommerceService service = new AWSECommerceService();
        service.setHandlerResolver(new AwsHandlerResolver(
                secretKey)); // important
        AWSECommerceServicePortType port = service.getAWSECommerceServicePort();

        // Get the operation object:
        com.ECS.client.jax.ItemSearchRequest itemRequest = new com.ECS.client.jax.ItemSearchRequest();

        // Fill in the request object:
        itemRequest.setSearchIndex("Books");
        itemRequest.setKeywords("Star Wars");
        // itemRequest.setVersion("2011-08-01");
        com.ECS.client.jax.ItemSearch ItemElement = new com.ECS.client.jax.ItemSearch();
        ItemElement.setAWSAccessKeyId(awsKey);
        ItemElement.getRequest().add(itemRequest);

        // Call the Web service operation and store the response
        // in the response object:
        com.ECS.client.jax.ItemSearchResponse response = port
                .itemSearch(ItemElement);

        String r = response.toString();
        System.out.println("response: " + r);

        for (Items itemList : response.getItems()) 
            System.out.println(itemList);
            for (Item item : itemList.getItem()) 
                System.out.println(item);
            
        

        System.out.println("API Test stopped");

    

这是我回来的内容。我希望看到亚马逊上的一些星球大战书籍被倾倒到我的控制台上:-/:

API Test started
response: com.ECS.client.jax.ItemSearchResponse@7a6769ea
com.ECS.client.jax.Items@1b5ac06e
API Test stopped

我做错了什么(请注意,第二个 for 循环中没有“项目”被打印出来,因为它是空的)?如何解决此问题或获取相关错误信息?

【问题讨论】:

【参考方案1】:

我不使用 SOAP API,但您的 Bounty 要求并没有说明它必须使用 SOAP,只是您想调用 Amazon 并获得结果。因此,我将使用 REST API 发布这个工作示例,它至少可以满足您的要求:

我想要一些可以访问亚马逊服务器并返回结果的工作示例代码

您需要下载以下内容以满足签名要求:

http://associates-amazon.s3.amazonaws.com/signed-requests/samples/amazon-product-advt-api-sample-java-query.zip

解压缩并获取com.amazon.advertising.api.sample.SignedRequestsHelper.java 文件并将其直接放入您的项目中。此代码用于签署请求。

您还需要从以下下载 Apache Commons Codec 1.3 并将其添加到您的类路径中,即添加到您项目的库中。请注意,这是唯一适用于上述类的 Codec 版本 (SignedRequestsHelper)

http://archive.apache.org/dist/commons/codec/binaries/commons-codec-1.3.zip

现在您可以复制并粘贴以下内容,确保将 your.pkg.here 替换为正确的包名称,并替换 SECRETKEY 属性:

package your.pkg.here;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

public class Main 

    private static final String SECRET_KEY = "<YOUR_SECRET_KEY>";
    private static final String AWS_KEY = "<YOUR_KEY>";

    public static void main(String[] args) 
        SignedRequestsHelper helper = SignedRequestsHelper.getInstance("ecs.amazonaws.com", AWS_KEY, SECRET_KEY);

        Map<String, String> params = new HashMap<String, String>();
        params.put("Service", "AWSECommerceService");
        params.put("Version", "2009-03-31");
        params.put("Operation", "ItemLookup");
        params.put("ItemId", "1451648537");
        params.put("ResponseGroup", "Large");

        String url = helper.sign(params);
        try 
            Document response = getResponse(url);
            printResponse(response);
         catch (Exception ex) 
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        
    

    private static Document getResponse(String url) throws ParserConfigurationException, IOException, SAXException 
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document doc = builder.parse(url);
        return doc;
    

    private static void printResponse(Document doc) throws TransformerException, FileNotFoundException 
        Transformer trans = TransformerFactory.newInstance().newTransformer();
        Properties props = new Properties();
        props.put(OutputKeys.INDENT, "yes");
        trans.setOutputProperties(props);
        StreamResult res = new StreamResult(new StringWriter());
        DOMSource src = new DOMSource(doc);
        trans.transform(src, res);
        String toString = res.getWriter().toString();
        System.out.println(toString);
    

如您所见,这比 SOAP API 更易于设置和使用。如果您对使用 SOAP API 没有特定要求,那么我强烈建议您改用 REST API。

使用 REST API 的一个缺点是结果不会为您解组到对象中。这可以通过基于 wsdl 创建所需的类来解决。

【讨论】:

我必须添加 params.put("AssociateTag","th0426-20") 才能让它工作,但是谢谢.. 肯定有一些进展。 不完全是我想要的,但我会给你分数,因为它让我朝着正确的方向前进。 我忘记了新的 Associate 标签要求。很高兴我能帮上忙。 @JonathanSpooner 使用此代码我如何解析输出并检索单个值?即,如果我只想要标题和定价? @Tukajo 提示:文档包含所有元素;)【参考方案2】:

这最终起作用了(我必须将我的 associateTag 添加到请求中):

public class Client 

    public static void main(String[] args) 

        String secretKey = "<MY_SECRET_KEY>";
        String awsKey = "<MY AWS KEY>";

        System.out.println("API Test started");


        AWSECommerceService service = new AWSECommerceService();
        service.setHandlerResolver(new AwsHandlerResolver(secretKey)); // important
        AWSECommerceServicePortType port = service.getAWSECommerceServicePort();

        // Get the operation object:
        com.ECS.client.jax.ItemSearchRequest itemRequest = new com.ECS.client.jax.ItemSearchRequest();

        // Fill in the request object:
        itemRequest.setSearchIndex("Books");
        itemRequest.setKeywords("Star Wars");
        itemRequest.getResponseGroup().add("Large");
//      itemRequest.getResponseGroup().add("Images");
        // itemRequest.setVersion("2011-08-01");
        com.ECS.client.jax.ItemSearch ItemElement = new com.ECS.client.jax.ItemSearch();
        ItemElement.setAWSAccessKeyId(awsKey);
        ItemElement.setAssociateTag("th0426-20");
        ItemElement.getRequest().add(itemRequest);

        // Call the Web service operation and store the response
        // in the response object:
        com.ECS.client.jax.ItemSearchResponse response = port
                .itemSearch(ItemElement);

        String r = response.toString();
        System.out.println("response: " + r);

        for (Items itemList : response.getItems()) 
            System.out.println(itemList);

            for (Item itemObj : itemList.getItem()) 

                System.out.println(itemObj.getItemAttributes().getTitle()); // Title
                System.out.println(itemObj.getDetailPageURL()); // Amazon URL
            
        

        System.out.println("API Test stopped");

    

【讨论】:

【参考方案3】:

看起来响应对象没有覆盖 toString(),所以如果它包含某种错误响应,简单地打印它不会告诉你错误响应是什么。您需要查看 api 以了解响应对象中返回的字段并单独打印这些字段。要么您会收到一条明显的错误消息,要么您必须返回他们的文档以尝试找出问题所在。

【讨论】:

是的,看看您是否可以使用 tcpmon 或类似工具来检查来自 Amazon 的 XML 响应。然后您就可以在他们的 XML 中看到完整的错误消息。【参考方案4】:

您需要调用 Item 对象的 get 方法来检索其详细信息,例如:

for (Item item : itemList.getItem()) 
   System.out.println(item.getItemAttributes().getTitle()); //Title of item
   System.out.println(item.getDetailPageURL()); // Amazon URL
   //etc

如果有任何错误,您可以通过调用 getErrors() 来获取它们

if (response.getOperationRequest().getErrors() != null)  
  System.out.println(response.getOperationRequest().getErrors().getError().get(0).getMessage());

【讨论】:

感谢您的输入,但是“response.getOperationRequest()”和“itemList.getItem()”都是空的,所以没有打印出来... :-\ 这可能是因为您没有为请求(see Amazon Product API Docs) 指定响应组。您可以通过以下方式在请求中添加响应组:itemRequest.getResponseGroup().add("Large"); itemRequest.getResponseGroup().add("Images");

以上是关于通过 Java/SOAP 的亚马逊产品广告 API的主要内容,如果未能解决你的问题,请参考以下文章

我没有通过亚马逊产品广告 API 获得价格

通过亚马逊产品广告 API 过滤或确定仓库交易?

可以通过亚马逊产品广告 API 检索 Kindle 电子书的实际价格吗?

如何从亚马逊的产品广告 API 中获取图片和描述?

连接到亚马逊产品广告 API 时出现“Access-Control-Allow-Origin”错误

亚马逊产品广告 api 获取带有优惠的产品