いやもう、タイトルの通りでございます。いつものAmazon to Rakutenに買い物かごをしれっと追加しました。まあ、つけた方が個人的に便利やし。そこで工夫した点など。
必要な情報
まず、実際の楽天ブックスの商品ページの買い物かごボタンを見て、どんなデータをPOSTしてやればいいのかを調べます。
<form method="post" action="https://books.step.rakuten.co.jp/rms/mall/book/bs/Cart"> <div> <span class="unit">個数 </span> <input value="1" type="text" size="4" name="units" id="units"> <input value="買い物かごに入れる" type="submit"> <input type="hidden" value="213310" name="shop_bid"> <input type="hidden" value="14034556" name="item_id" id="ScItemGet"> <input type="hidden" value="1" name="inventory_flag"> </div> </form>
見た感じ、いじる必要がありそうなとこは、
1.「個数」をhiddenで1個に固定
2."item_id"を商品に合わせて変更
2."item_id"を商品に合わせて変更
の2点。楽天ブックスは楽天市場の1店舗なので、"shop_bid"は全部一緒のはず。"inventory_flag"は、まあようわからんけどこのままでいいっしょ。
実装
ということで、実質コードを書く必要があるのは"item_id"だけ。ところが厄介なことに、"item_id"はなんとAPIに入っていないので、もっかいXMLHttpRequestを叩いて無理矢理取ってくることに。http通信2回分なんて待ってられないので、一回目のAPI通信で取得したデータはすぐ表示しつつ、続けてitem_idが取得出来次第ボタンを表示っていう仕様にしました。
chrome.extension.onConnect.addListener(function(port) {
console.assert(port.name == "AtoR");
port.onMessage.addListener(function(msg) {
if(msg.status == "start"){
//ページアクションのアイコンを表示
chrome.pageAction.show(port.sender.tab.id);
//楽天APIから商品を検索
query = "http://api.rakuten.co.jp/rws/3.0/json?" +
"developerId=" + devId +
"&affiliateId=" + afiId +
"&operation=" + opr +
"&version=" + ver+
"&keyword=" + encodeURI(msg.title);
api.open("GET",query,true);
api.onreadystatechange = sourceGet(port);
api.send(null);
}
else if(msg.status == "null"){
content = "このページでは使用できません。";
}
else{
sourceGet(port);
}
});
});
//タブが変更された時の処理
chrome.tabs.onSelectionChanged.addListener(function(tabid){
chrome.tabs.getSelected(null, function(tab) {
・・・
});
});
function sourceGet(port){
if (api.readyState == 4 && api.status == 200){
response = eval('[' + api.responseText + ']')[0];
if(response['Header']['Status'] == 'Success'){
items = response['Body']['BooksTotalSearch']['Items']['Item'];
//商品データを1つずつhtmlに出力
content = '<table width="300">';
for(i=0;i<items.length;i++){
content = content+'<tr><td><a href="'+items[i]['affiliateUrl']+'"><img src="'+items[i]['mediumImageUrl']+'" /></a></td><td style="width:200px;vertical-align:top;">タイトル:<a href="'+items[i]['affiliateUrl']+'" target="_blank">'+items[i]['title']+'</a><br />著者:'+items[i]['author']+'<br />価格(税込):'+setComma(items[i]['itemPrice'])+'円<br />ポイント:'+Math.floor(items[i]['itemPrice']/1.05/100)+'ポイント<br /><img src="img/star_';
if(items[i]['reviewAverage'] == 0) content = content + '0';
else if(items[i]['reviewAverage'] > 0 && items[i]['reviewAverage'] < 1) content = content + '0.5';
else if(items[i]['reviewAverage'] == 1) content = content + '1';
else if(items[i]['reviewAverage'] > 1 && items[i]['reviewAverage'] < 2) content = content + '1.5';
else if(items[i]['reviewAverage'] == 2) content = content + '2';
else if(items[i]['reviewAverage'] > 2 && items[i]['reviewAverage'] < 3) content = content + '2.5';
else if(items[i]['reviewAverage'] == 3) content = content + '3';
else if(items[i]['reviewAverage'] > 3 && items[i]['reviewAverage'] < 4) content = content + '3.5';
else if(items[i]['reviewAverage'] == 4) content = content + '4';
else if(items[i]['reviewAverage'] > 4 && items[i]['reviewAverage'] < 5) content = content + '4.5';
else if(items[i]['reviewAverage'] == 5) content = content + '5';
content = content + '.png" />('+items[i]['reviewCount']+')<br />買い物かごに入れる</td></tr>';
rakuten.open("GET",items[i]["itemUrl"],true);
rakuten.onreadystatechange = function(){
if (rakuten.readyState == 4 && rakuten.status == 200){
rr = rakuten.responseText;
rr.match(/value="([^"]*)"[^>]*id="ScItemGet"/);
rr = RegExp.$1;
//買い物かご
cart = '<form method="post" action="https://books.step.rakuten.co.jp/rms/mall/book/bs/Cart" target="_blank">';
cart = cart + '<div>';
cart = cart + '<input value="1" type="hidden" name="units" id="units">';
cart = cart + '<input value="買い物かごに入れる" type="submit">';
cart = cart + '<input type="hidden" value="213310" name="shop_bid">';
cart = cart + '<input type="hidden" value="'+rr+'" name="item_id" id="ScItemGet">';
cart = cart + '<input type="hidden" value="1" name="inventory_flag">'
cart = cart + '</div>'
cart = cart + '</form>'
content = content.replace("買い物かごに入れる", cart);
viewContent();
}
};
rakuten.send(null);
}
content = content+'</table>';
viewContent();
}
・・・
}
・・・
}
61行目で、まずベタ文字で「買い物かごに入れる」って表示しつつ、63行目以下で2度目の通信を行ってます。item_idは67行目の正規表現で強引にゲット。正規表現が一発で決まると気持ちいい。
無事にitem_idが取れたらベタ文字をformタグで置換。めでたしめでたし。

