為さねば成らぬ

retia.verno@gmail.com

APIのデータ解析

PixivだとiPhone用のAPIでランキングや検索結果がデータとして取得できるわけだが、これがめんどくさい。

例としてデイリーランキング取るとすると、
http://iphone.pxv.jp/iphone/ranking.php?mode=day
を叩くが、その結果がこちら。

"16774382","426002","jpg","レミリア咲夜","21","かる","http://img21.pixiv.net/img/amethyst21/mobile/16774382_128x128.jpg",,,"http://img21.pixiv.net/img/amethyst21/mobile/16774382_480mw.jpg",,,"2011-02-18 19:23:42","東方" "レミリア" "咲夜" "なにこれかっこいい" "ふつくしい" "なにこれすごい" "紅魔郷" "咲レミ" "東方Project1000users入り",,"3773","37378","85199",,,,,"2417","8","amethyst21",,  ・・・

xmlとかjsonとかじゃなく、 " と , で区切られてる・・・
つーことでちょいと解析。

1作品は改行にて区切られており(キャプション中の区切りもあるため注意)さらにそれらは26個の詳細情報が含まれている。この区切りは , 。

詳細情報については頭から以下。

  1. 作品ID
  2. 作者ID(数字)
  3. 拡張子
  4. タイトル
  5. サーバ番号
  6. 作者名
  7. 128x128画像のURL
  8. ?
  9. ?
  10. 480mw画像のURL
  11. ?
  12. ?
  13. 投稿日時
  14. タグ
  15. 使用ソフト
  16. 評価回数
  17. 総合点
  18. 閲覧数
  19. キャプション
  20. ページ数
  21. ?
  22. ?
  23. ?*1
  24. ?*2
  25. 作者ID(ユーザー名)
  26. ?

?は不明。基本的に値が入っていないものがほとんどだが、*1*2は入ってる値が謎なもの。*1は見た感じ4桁くらいの数字だけどapi叩くごとに値が増えるから評価とかと関係があるかも。*2は2桁ってことくらいでよくわからん。


画像URLのあたりの不明なのは未実装のサイズの画像のURLを格納するんかなーと思ってみたり。つーかそもそも
http://imgサーバ番号(2桁).pixiv.net/img/作者ID(ユーザー名)/mobile/作品ID_画像サイズ.拡張子
が画像のURLになるからわざわざURL含めないでもいい気がするけどねー。ちなみにPC用画像にも直接アクセス可能。ログイン済みでクッキー必要だけど。


解析した結果のリストを返すJAVAソースコードはこちら。

public ArrayList<HashMap<String, String>> getRankingItems(){
		try {
			URL url = new URL(
					"http://iphone.pxv.jp/iphone/ranking.php?mode=day");
			HttpURLConnection con = (HttpURLConnection) url.openConnection();
			BufferedReader br = new BufferedReader(new InputStreamReader(
					con.getInputStream(), "utf-8"));
			String line;
			StringBuffer str = new StringBuffer();
			ArrayList<String> details = new ArrayList<String>();
			while ((line = br.readLine()) != null) {
				str.append(line);
			}
			parse(details, str.toString().split(",", 2));
			ArrayList<HashMap<String, String>> items = new ArrayList<HashMap<String, String>>();

			for (int i = 0; i < details.size() / 26; i++) {	
				HashMap<String, String> item = new HashMap<String, String>();
				item.put("id", details.get(i*26));
				item.put("authorid", details.get(i*26+1));
				item.put("extension", details.get(i*26+2));
				item.put("title", details.get(i*26+3));
				item.put("server", details.get(i*26+4));
				item.put("authorname", details.get(i*26+5));
				item.put("128url", details.get(i*26+6));
				item.put("?1", details.get(i*26+7));
				item.put("?2", details.get(i*26+8));
				item.put("480url", details.get(i*26+9));
				item.put("?3", details.get(i*26+10));
				item.put("?4", details.get(i*26+11));
				item.put("time", details.get(i*26+12));
				item.put("tag", details.get(i*26+13));
				item.put("soft", details.get(i*26+14));
				item.put("review", details.get(i*26+15));
				item.put("score", details.get(i*26+16));
				item.put("view", details.get(i*26+17));
				item.put("caption", details.get(i*26+18));
				item.put("page", details.get(i*26+19));
				item.put("?5", details.get(i*26+20));
				item.put("?6", details.get(i*26+21));
				item.put("?7", details.get(i*26+22));
				item.put("?8", details.get(i*26+23));
				item.put("userid", details.get(i*26+24));
				item.put("?9", details.get(i*26+25));
				items.add(item);
			}
			return items;	
		} catch (Exception e) {
			return null;
		}
	}

	public String parse(ArrayList<String> details, String[] strarr) {
		if (strarr.length != 2) {
			return null;
		} else if (strarr[0].isEmpty() || strarr[0].startsWith("\"")
				&& strarr[0].endsWith("\"")) {
			details.add(strarr[0]);
			strarr = strarr[1].split(",", 2);
			return parse(details, strarr);
		} else if (strarr[1].isEmpty() || strarr[1].startsWith("\"")
				&& strarr[1].endsWith("\"")) {
			return strarr[1];
		} else {
				String[] strarr2 = strarr[1].split(",", 2);
				strarr[0] = strarr[0].concat(strarr2[0]);
				strarr[1] = strarr2[1];
			return parse(details, strarr);
		}
	}

parse()にて , で区切った詳細情報をdetailsのリストに放り込んであとは26個ごとにitemsにマッピングして突っ込むだけ。キャプション中に区切り文字の , が含まれてるといけないから安易にsplit()は使えなかったけどもうちょい効率いいのあるかも。


とりあえずこれ使ってviewerの実装やってきましょか