Bookmarkletを作ろう(実践編)

javascriptとjqueryでBookmarkletを作ろうの第三回

#はじめに
[前回](https://qiita.com/kanaxx/items/1d8f6c0b1a292592974e)までで、BookmarkletでjQueryを動かす下地ができたので、そこに具体的にコードを埋め込んでbookmarkletを作り上げていきます。
※このサンプルは他人さまのウェブページのHTMLをほじくり倒すので、HTMLの構造が変わってしまったら動かなくなることがあります。

#使うもの
- javascript
- jQuery3

#作るもの
楽天の商品ページから、いろんな情報を探してピックアップして表示するものを作ってみます。

##サンプルURL
https://item.rakuten.co.jp/soukaidrink/9000009984074/
クリスタルガイザー(500mL*48本入)

楽天の商品ページです。普通のjavascriptで正規表現使ってみたり、jqueryで値を引っ張ってみたりやっていますが、正解はありませんので参考程度に見てください。

##作成したbookmarklet全体

```javascript
javascript:void((function(f){
  // jQueryの存在チェックとバージョンチェック
  if(window.jQuery && jQuery().jquery > '1.8') {
    // jQueryが存在していればそれをそのまま使う
    f(jQuery);
  }else{

    var script = document.createElement('script');
    script.src = '//code.jquery.com/jquery-3.2.1.min.js';
    
    script.onload = function(){
      var $ = jQuery.noConflict(true);
      f($);
    };

    document.body.appendChild(script);
  }
})(
function($, undefined){
  // バージョン確認
  ;;; console.log('jQuery: ', $().jquery);

  //１．URLチェック
  if( !location.href.match(/item.rakuten.co.jp/)){
    alert('対象ページではありません');
    return;
  }

  //２．urlから値を取る
  console.log(location.pathname);
  if( location.pathname.match(/\/([^\/]*)\/([^\/]*)/)){
    console.log('shop url:'+RegExp.$1);
    console.log('item url:'+RegExp.$2);
  }

  //３．formの値を取る
  console.log('shop id:' +$('input[type="hidden"][name="shop_bid"]').val());
  console.log('item id:' + $('input[type="hidden"][name="item_id"]').val());

  //４．bodyのHTMLをテキスト処理
  htmlbody = document.body.innerHTML;
  if( htmlbody.match(/商品レビューを見る（([0-9,]*)件）/)){
    console.log('review count:' + RegExp.$1);
  }

  //５．json文字列をいただく（複数行は面倒なので改行は全消し）
  htmlbody = htmlbody.replace(/\n/g, '');

  //schema orgのテキストを横取り
  if( htmlbody.match(/<script type="application\/ld\+json">(.*?)<\/script>/)){
    console.log(RegExp.$1);
    schema_org = eval("(" +RegExp.$1+")");
    console.log(schema_org);
    console.log(schema_org['itemListElement'][0]['item']['name']);
  }else{
    console.log('un match');
  }

  //６．bookmarkletの起動を制御するコード
  //初回だったらdivタグを突っ込み、2日目以降はタグの値をカウントアップ
  if( $('div#executed').length ){
    cnt = $('div#executed').text();
    cnt ++;
    console.log(cnt +'回目');
    $('div#executed').text(cnt);

    //2回動くのが都合が悪いなら
    //return;
  }else{
    $('body').prepend('<div id="executed">1</div>');
  }

  //７．特定の要素を囲む、要素を追加する
  $('span.item_name').wrap('<div id="bmlet01"></div>');
  $('div#bmlet01').append('<div id="bmlet01_title">item name</div>');

  //自分で追加した要素にCSS
  $('div#bmlet01').css({'border':'solid'});
  $('div#bmlet01_title').css({'background-color':'red','color':'white'});
  
  //８．ページ画像のON/OFF
  $('img').toggle();
  //画像を全てOFF
  //$('img').hidden();

}
)
);
```

実行結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/168315/0a230102-0379-dab2-0560-5974d6abd280.png)



コードの解説をしていきます。

###解説１

```javascript
  //１．URLチェック
  if( !location.href.match(/item.rakuten.co.jp/)){
    alert('対象ページではありません');
    return;
  }
```

表示しているURLがbookmarkletの対象としているか確認をします。正規表現で確認しています。対象でない場合にはreturnしてしまいましょう。後続の処理は動きません。

###解説２

```javascript
  if( location.pathname.match(/\/([^\/]*)\/([^\/]*)/)){
    console.log('shop url:'+RegExp.$1);
    console.log('item url:'+RegExp.$2);
  }
```

楽天のURLの後半部分には、店のIDと商品のIDが埋め込まれているので、これを正規表現で刈り取っています。エスケープ文字があるので読みにくいですが、先頭がスラッシュ、スラッシュ以外の繰り返し、スラッシュ1回、スラッシュ以外の繰り返し、という意味です。

###解説３

```javascript
  //３．formの値を取る
  console.log('shop id:' +$('input[type="hidden"][name="shop_bid"]').val());
  console.log('item id:' + $('input[type="hidden"][name="item_id"]').val());
```

フォームの内容は、jQueryを使うととっても簡単に参照できます。hiddenでも楽ちん。IDで参照しない場合はフォームの部品が複数取れてしまうかもしれません。


###解説４

```javascript
  //４．bodyのHTMLをテキスト処理
  htmlbody = document.body.innerHTML;
  if( htmlbody.match(/商品レビューを見る（([0-9,]*)件）/)){
    console.log('review count:' + RegExp.$1);
  }
```

次は、bodyのHTML全体から何かを探すサンプルです。今回はレビューの件数を正規表現で取り出しています。「レビューを見る（000件）」という部分をちょっとでも返られたらアウトです。

###解説５

```javascript
//５．json文字列をいただく（複数行は面倒なので改行は全消し）
  htmlbody = htmlbody.replace(/\n/g, '');

  //schema orgのテキストを横取り
  if( htmlbody.match(/<script type="application\/ld\+json">(.*?)<\/script>/)){
    console.log(RegExp.$1);
    schema_org = eval("(" +RegExp.$1+")");
    console.log(schema_org);
    console.log(schema_org['itemListElement'][0]['item']['name']);
  }else{
    console.log('un match');
  }
```

これも上の４と同じく、HTML全体から文字列の抜き出しなのですが、複数行の文字列の場合は正規表現が面倒なので取り出す前に改行を全部置き換えています。正規表現でマッチした部分（<script></script>の間の文字列）がjsonの文字列なので、evalしてオブジェクト化しています。オブジェクト化した変数は、配列構造になっているのでこんな感じで参照可能です。


###解説６

```javascript

//６．bookmarkletの起動を制御するコード
  //初回だったらdivタグを突っ込み、2日目以降はタグの値をカウントアップ
  if( $('div#executed').length ){
    cnt = $('div#executed').text();
    cnt ++;
    console.log(cnt +'回目');
    $('div#executed').text(cnt);

    //2回動くのが都合が悪いなら
    //return;
  }else{
    $('body').prepend('<div id="executed">1</div>');
  }
```

このコードは、bookmarkletが2回以上動かないように制御するためのものです。Bodyのすぐ下に勝手に```<div>```タグを忍び込ませ、カウントを数えています。jQueryが使えるとこの辺のコードも簡単です。```<div>```のidが既存のidと被らないように適当に変えてください。2重起動を防止するのであれば、URLチェックの後に動かすのがいいでしょう。


###解説７

```javascript
  //７．特定の要素を囲む、要素を追加する
  $('span.item_name').wrap('<div id="bmlet01"></div>');
  $('div#bmlet01').append('<div id="bmlet01_title">item name</div>');

  //自分で追加した要素にCSS
  $('div#bmlet01').css({'border':'solid'});
  $('div#bmlet01_title').css({'background-color':'red','color':'white'});
```

このコードは、HTMLのパーツを分かりやすくするためのサンプルです。タグ、ID、クラス名あたりで名指しして```<div>```で囲って目立たせています。jQuery使うと簡単です。
もともとのHTMLを汚染しますので、何度も実行するとどんどん汚くなります。


###解説８

```javascript
  //８．ページ画像のON/OFF
  $('img').toggle();
  //画像を全てOFF
  //$('img').hidden();
```

楽天の商品ページには縦に長い画像が多いですからね、、全部OFFするならこんな感じです。特定の要素の下の画像だけ非表示にするとか、jQueryのセレクタを書き換えれば自由にできるはずです。

#まとめ
bookmarkletとjQueryを使うとページ内に埋め込まれた値を抜き出したり、要素を強調したり、不要なところを隠したりということが簡単にできます。受け取ったHTMLだけで何かするトリックはこれくらいでしょうか。本番にデプロイするコードには不要だけど、開発中やリリース後にデバッグ用にあったら便利なものは、bookmarklet化して配っておくのはいかがでしょう。

このページの商品コードって何だっけ？みたいな作業って、何度も発生しませんか？bookmarkletにして一発で探せるようにしておくと作業効率が上がります。

次回は、ページ内にある要素を抜き出した後にajaxで非同期通信するサンプルを作ってみます。