Hatena::Diary

5.1さらうどん

2009/04/21(Tue)

[][]Amazon価格.comの最低価格を表示する『Amazon Lowest Price Checker』改良版リリースしました 23:29 はてなブックマーク - Amazonに価格.comの最低価格を表示する『Amazon Lowest Price Checker』改良版リリースしました - 5.1さらうどん

http://gyazo.com/448a2c48cc0cbdfcffd7946a879fc785.png

どうせ既に誰かが作っているだろうから習作にちょうど良い、と思って作ったGreasemonkeyがまさかここまで評価していただけるとは夢にも思いませんでした。

Amazonで閲覧中の商品に価格comから最低価格を取ってきて付加するGreasemonkeyスクリプト書いた - 5.1さらうどん


ここまで評価されたことに対して純粋な喜びもさることながら、それ以上に、こんな適当で不完全な物を衆目に晒してしまったことが非常に申し訳ない。

ということで、既知の問題点含め、可能な限り改良してみた。

大学の空きコマを使ってちまちまと作り続け、1日がかりで完成させました。

どうぞご利用ください。


ダウンロードこちらから。

Amazon Lowest Price Checker


Greasemonkey固有の関数を使っているため、Operaなどでは動かないと思います。

改良、バグ報告等をお待ちしております。

主な改良点まとめ


・Amazonでの価格との価格差を表示させるようにしました

おそらく今回一番大きな改良点。

価格.comからの取得よりもAmazonのページ内から価格を取得する方が大変だったw

Amazonはページによって価格の表示形式が統一されていないので、3カ所ぐらいチェックして取得できた物を採用しています。

かなり強引に作った感じなので、バグが一番多い箇所かも。

価格差が0円の場合は表示されません。

その他にも、表示がおかしくなってしまう場合は強引に表示を消したりしています。

そのため、たまに価格差が表示されないこともあります。


・価格.com該当ページへのリンクを追加しました

コメント欄にも要望があった機能を追加。

価格にリンクを貼ろうとも考えましたが、結局今の形に落ち着きました。


・値段を3桁区切りで表示するようにしました

他の価格の表示と統一感が無かったのが気になったので付けてみました。

正規表現での記述方法がいまいちよくわからなかったので、以下のサイトを参考にしました。

Javascriptで金額表示に使う3桁区切り、カンマ挿入|Webで使えるテクニック!Webで困ったときのメモ帳


・読み込み中画面を追加しました

http://gyazo.com/5b5445ea4c5cd5317d59825a7d73224d.png

動いているかよくわからないというご指摘があったので、ロード画面を付けてみた。

f:id:gigi-net:20090421143419g:image


ローディングアイコンは以下のサイトから生成しました。

Load Info - gif generator


エラーメッセージを追加しました

http://gyazo.com/f88f0cec74d7b8c60cf7de70c3ade4f2.png

http://gyazo.com/29d5c26a3f8822feaa4c7abe62074895.png

ページ内から型番が取得できなかった場合は上が、型番を検索しても価格.comから結果が戻ってこなかった場合下が表示されます。


・価格.comのライセンス表示をしました

http://gyazo.com/590895a1d8a4512eb2afb8956e5da777.png

コメント欄で中の人にまでいろいろとお世話になったので追加してみた。


メーカー型番の取得アルゴリズムを強化しました

前回のエントリで触れたように、メーカー型番という文字列が含まれる項目を全て探す仕様にしてみた。

コメント欄で別の取得方法も提案していただきましたが、実際に試してみても現行のアルゴリズムの方が良い感じだったので採用しませんでした。


・その他、細かい修正を施しました

価格.comからの取得に使うAPIバージョンを変更しました。

価格.com WEBサービス API マニュアル


また、¥の表示方式を変更しました。

商品ページ以外の検索ページなどでもたまに誤作動してしまうことがあったので、商品ページかどうか判定させる仕様にしました。


既知の問題点

・表示される価格が別の商品である可能性がある

前回ご指摘頂いたマウスの件もそうですが、ごく希に検索結果に別の商品がひっかかることがあるようです。

http://gyazo.com/78c4e2b4a745768a83529f70c1f8531d.png


メーカー型番が短い商品だと誤作動が起こりやすくなるようです。

発生率は限りなく低いですが、以上のように不自然な価格差が生じた場合は鵜呑みにせずに価格.comの該当ページを閲覧されることをお勧めします。


手動検索機能については、いろいろと煩雑になりそうなので今回のところは見送りました。

最後に

ブログなどで紹介していただいた方はありがとうございます。

トラックバックを送っていただいた記事については全てチェックしました。


ついカッとなって - BlueberryStream

以上のページで、僕が作成した物の改良版が公開されているようなのでぜひ。

ソース

// ==UserScript==
// @name           Amazon Lowest Price Checker
// @namespace      http://gigi-net.net
// @include        http://www.amazon.co.jp/*
// ==/UserScript==
(function(){
//価格を3ケタ区切りにする関数
function SetPrice(price){
 var num = new String(price).replace(/,/g, "");
 while(num != (num = num.replace(/^(-?\d+)(\d{3})/, "$1,$2")));
 return num;
}


//価格を数値に変換
function ConvertPrice(price){
	var result="";
	for(var i =0;i<6;i++){
		price = price.replace(/\D+/,"")
		result =price;
	}
	return parseInt(result);
}

//APIURL定義
var api_url ="http://api.kakaku.com/Ver1.1/ItemSearch.aspx";

//商品ページかどうか判定
	a = document.getElementById("buyboxTable");
	if(a ==null){
	var flag =0;
	}else{
	var flag =1;
	}


if(flag ==1){
//ロード中メッセージ表示
var title =document.getElementsByTagName("h1");
var check_lowest =document.createElement("div");
check_lowest.innerHTML ="<img src='http://img.f.hatena.ne.jp/images/fotolife/g/gigi-net/20090421/20090421143419.gif?1240292104' style='vertical-align:middle'>価格.comから最低価格を読み込んでいます。";
title[0].parentNode.appendChild(check_lowest);

//製品型番を取得
var kataban ="";
try{
	var dom_kataban =document.getElementById("productDetailsDiv").childNodes[0];
	for(var i=0;i<dom_kataban.childNodes.length;i++){
		if(dom_kataban.childNodes[i].innerHTML.indexOf("メーカー型番") !=-1){
			kataban = dom_kataban.childNodes[i].innerHTML;
		}
	}
}catch(e){
	var kataban ="";
}
if(kataban !=""){
	kataban =kataban.replace(/<.*>/,"");
}else{
	check_lowest.innerHTML ="<b>Error:</b>商品の型番が取得できませんでした。";
	title[0].parentNode.appendChild(check_lowest);
}
//価格comAPIを用いて型番から最安値を取得
xml_url =api_url +"?Keyword="+encodeURIComponent(kataban)+"&CategoryGroup=ALL&SortOrder=pricerank&HitNum=5";

//Amazon.comの価格を取得
var ap =0;
try{
var amazon_price = document.getElementById("buyboxPriceBlock");
amazon_price = amazon_price.getElementsByTagName("table")[0];
amazon_price = amazon_price.getElementsByTagName("tbody")[0]
amazon_price = amazon_price.getElementsByTagName("tr");
	var table = amazon_price[0].getElementsByTagName("td");
		if(table[0].getElementsByTagName("b")[1].getAttribute("class") =="price"){
		ap = table[0].getElementsByTagName("b")[1].innerHTML;
		}else if(table[0].getElementsByTagName("span")[0].getAttribute("class") =="price"){
		ap = table[0].getElementsByTagName("span")[0].innerHTML;
		}
}catch(e){
try{
var ap =0;
var amazon_price = document.getElementById("priceBlock");
amazon_price = amazon_price.getElementsByTagName("table")[0];
amazon_price = amazon_price.getElementsByTagName("tbody")[0]
amazon_price = amazon_price.getElementsByTagName("tr");
for(var i=0;i<amazon_price.length;i++){
	var table = amazon_price[i].getElementsByTagName("td");
	if(table[0].innerHTML.indexOf("価格") == 0){
		if(table[1].getElementsByTagName("b")[0].getAttribute("class") =="priceLarge"){
		ap = table[1].getElementsByTagName("b")[0].innerHTML;
		}else if(table[1].getElementsByTagName("span")[0].getAttribute("class") =="priceLarge"){
		ap = table[1].getElementsByTagName("span")[0].innerHTML;
		}
	}
	}
}catch(e){
	var ap =0;
	}
}
ap = ConvertPrice(ap);


//価格表示関数
function ShowPrice(x){
	var parser = new DOMParser();
	var xml = parser.parseFromString( x.responseText, "text/xml" );
	if(xml.childNodes[0].childNodes[0].textContent =="ItemNotFound"){
		check_lowest.innerHTML="<b>Error:</b>価格.comで該当商品が見つかりませんでした。";
	}else{
		var dom_price = xml.getElementsByTagName("ProductInfo")[0].getElementsByTagName("Item")[0].getElementsByTagName("LowestPrice");
		var pageurl = xml.getElementsByTagName("ProductInfo")[0].getElementsByTagName("Item")[0].getElementsByTagName("ItemPageUrl");
		price = dom_price[0].textContent;
		var sa =ap-price;
		check_lowest.innerHTML ="<b>最低価格:<span class='priceLarge'> &yen;  "+SetPrice(price)+"</span></b>";
		if(sa>0&&ap!=0&&sa<100000){
		check_lowest.innerHTML += " <font size=3>  Amazonより<span class='priceLarge'> &yen; "+SetPrice(sa)+"</span>安く買えます。</font>";
		}
		check_lowest.innerHTML +="<font size=3><a target='_blank' href="+pageurl[0].textContent+">価格.comを見る</a></font>";
		check_lowest.style.fontSize ="18px";
	}
	title[0].parentNode.appendChild(check_lowest);
}

//APIからXMLを読み込んで表示する。
if(kataban !=""){
	GM_xmlhttpRequest({
	  method:"GET", 
	  url:xml_url,
	  onload:ShowPrice
	});
};

//著作表示
var powered =document.createElement("div");
powered.innerHTML +=" <center>powered by <a href ='http://kakaku.com/'>価格.com</a></center>";
document.body.appendChild(powered);
}

})();

IronnackIronnack 2009/04/24 08:30 インストールしようとすると

スクリプト: C:\Documents and Settings\admin\デスクトップ\amazon_lowest_price_checker.user.js
行: 9
文字: 2
エラー: 文字が正しくありません。
コード: 800A03F6
ソース: Microsoft JScript コンパイル エラー

ってなるんですけど
これってどういう意味なんですか?

otnotn 2009/04/30 22:10 >Ironnackさん
Firefoxを使っている&Greasemonkeyアドオンをインストールしてある
という前提条件を満たしていますか?
満たしている場合にはリンクをクリックするとインストールできます。

IronnackIronnack 2009/05/09 00:56 >otnさん
これは失礼しました
Firefoxインストールしてませんでした
お騒がせしました

gigi-netgigi-net 2009/05/09 01:21 >Ironnackさん
管理者なのに放置していてすみません。
代わりに回答してくれた方ありがとうございます。
Firefoxだけではなく、Greasemonkeyというアドオンをインストールする必要があります。

pospos 2009/05/11 17:47 Errorばかりで困っています。使い方が悪いのでしょうか?

こんな感じです。
「Error:商品の型番が取得できませんでした。」

pospos 2009/05/11 17:52 自己レスです。パソコン関連の商品ではエラーばかりで1つも表示されなくて、使い方がおかしいのかなあと思ったのですが、液晶TVのところに行ってみるとちゃんと表示されました。

haru-sharu-s 2009/07/27 11:59 とても便利なスクリプトですね.
ありがとうございます.
価格だけだと別の商品と誤認したときに判断が難しいので価格.comの方に画像があればそれも表示してはいかがでしょうか.
価格が大きく異なるときだけ付加情報を表示するとかも考えられるかと.

gigi-netgigi-net 2009/07/30 08:18 なるほど。
ご意見ありがとうございます。
いろいろと表示がごたごたしてしまうので、しばらくはリンクだけで良いかと考えていますw

nonhikononhiko 2009/12/23 01:13 「価格.comから最低価格を読み込んでいます。」から一向に進みません。firefoxはバージョン3.5.6です。なぜでしょうか?

通りすがりさん通りすがりさん 2009/12/27 16:14 価格.comのWebサービスAPIが変わってしまったために、ずーーーっと、「価格.comから最低価格を読み込んでいます。」となります。

価格.comのWebサービスAPIの仕様を確認しているときに気付きました。従って、現時点ではこのスクリプトは動作しません。動作させるなら、ご自分で価格.comのWebサービスAPIキーを取得して、スクリプトを修正すれば動作しますが・・・。

ところで、作者さんはどうして報告してくれないのでしょうか?