プログラマとプロマネのあいだ

プログラマもやるし、プロマネもやるし、たまに似非アーキとか営業っぽいこともやるITエンジニアがスキルアップの話を中心に日常を綴るブログです。

Amazon Web Serviceを使って、ASINから本のトップカテゴリ名一覧を取得する

昨日書いた、読書ポートフォリオという考え方の続き。


便利なラッパーとかありそうだと思ったのだが、意外になかった(探し足りないだけ?)ので、とりあえずASINから本のトップカテゴリ名一覧を取得するところだけ作ってみました。
ここでは、図解入門業界研究 最新旅行業界の動向とカラクリがよーくわかる本 (How‐nual Industry Trend Guide Book)のカテゴリ一覧を取得してます。

Main.java

import org.w3c.dom.*;

public class Main
{
	public static void main(String[] args) throws Exception
	{
		AWSWrapper aws = new AWSWrapper("awsAccessKeyId");
		Document itemLookupResponse = aws.itemLookup("4798013390");
		String[] categories = AWSUtil.getCategoriesFromItemLookupResponse(itemLookupResponse);

		for(String category : categories)
		{
			System.out.println(category);
		}
	}
}

AWSWrapper.java

import javax.xml.parsers.*;
import org.w3c.dom.*;

public class AWSWrapper
{
	private String awsAccessKeyId;

	/**
	 *	awsAccessKeyIdを受け取って構築
	 */
	public AWSWrapper(String awsAccessKeyId)
	{
		this.awsAccessKeyId = awsAccessKeyId;
	}

	/**
	 *	itemLookupオペレーションのラッパ
	 */
	public Document itemLookup(String asin) throws Exception
	{
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();

		return db.parse(buildItemLookupURI(asin));
	}

	/**
	 *	itemLookupオペレーション用のURI生成
	 */
	private String buildItemLookupURI(String asin)
	{
		StringBuilder sb = new StringBuilder("http://ecs.amazonaws.jp/onca/xml?Service=AWSECommerceService&AWSAccessKeyId=");
		sb.append(awsAccessKeyId);
		sb.append("&Operation=ItemLookup&ResponseGroup=BrowseNodes&ItemId=");
		sb.append(asin);

		return sb.toString();
	}
}

AWSUtil.java

import java.io.*;
import java.util.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;

public final class AWSUtil
{
	private AWSUtil()
	{
		throw new RuntimeException("AWSUtilはインスタンス化できません。");
	}

	/**
	 *	itemLookupのResponseより、カテゴリ名一覧を返却する
	 */
	public static String[] getCategoriesFromItemLookupResponse(Document d)
	{
		Set<String> resultSet = new HashSet<String>();

		NodeList nl = d.getElementsByTagName("BrowseNode");
		for(int i=0; i<nl.getLength(); i++)
		{
			Node node = nl.item(i);
			if("ジャンル別".equals(getSecondChildNodeValue(node)))
			{
				resultSet.add(getSecondChildNodeValue(getGrandparentNode(node)));
			}
		}

		return resultSet.toArray(new String[0]);
	}

	/**
	 *	指定ノードの2番目の子の値を取得(子が2つ以上ない場合はnullを返す)
	 */
	private static String getSecondChildNodeValue(Node node)
	{
		NodeList nl = node.getChildNodes();
		if(nl.getLength() >= 2)
		{
			Node secondNode = nl.item(1);
			return secondNode.getFirstChild().getNodeValue();
		}
		else
		{
			return null;
		}
	}

	/**
	 *	指定ノードの親の親のノードを取得
	 */
	private static Node getGrandparentNode(Node node)
	{
		return node.getParentNode().getParentNode();
	}
}

結果はこう出ました。

旅行ガイド
ビジネス・経済・キャリア

ポイントは昨日も書いた、

  • リクエストパラメータにResponseGroup=BrowseNodesを付けること

  • ジャンル別で引っ掛けて、その上のカテゴリを持ってきていること

ですかね。


あとは、全ASINに対して同じことをやって集計すれば、カテゴリごとの読書数分析ってのもできるはず。


追記
Main.javaを改造して、stocks.csvを読み込んでカテゴリ名をだらだら出すように変えてみた。
stocks.csvは↓からダウンロードできます。
http://stack.nayutaya.jp/user/taka_2/export/stocks.csv

Main.java

import java.io.*;
import org.w3c.dom.*;

public class Main
{
	public static void main(String[] args) throws Exception
	{
		AWSWrapper aws = new AWSWrapper("awsAccessKeyId");

		BufferedReader br = new BufferedReader(new FileReader("stocks.csv"));

		String buf = "";
		while((buf = br.readLine()) != null)
		{
			String asin = buf.substring(1, 11);

			Document itemLookupResponse = aws.itemLookup(asin);
			String[] categories = AWSUtil.getCategoriesFromItemLookupResponse(itemLookupResponse);

			for(String category : categories)
			{
				System.out.println(category);
			}
		}
	}
}