77Lifeworkベータ版

77Lifeworkベータ版

IT関係の話(ツール開発・インフラ構築)をメインとして、その他私の趣味や雑記用のブログです。ここに書いた内容が少しでも参考になれば嬉しいです。

【初心者向け】GASでWebサイトをスクレイピングする方法(2)

はじめに

こんにちは。今回の記事はタイトルの通り、前回の「【初心者向け】GASでWebサイトをスクレイピングする方法(1)」の続きの内容となります。

記事の趣旨については前回の記事を読んでみてください。
www.77-lifework.com



前回はヤマダウェブコムを対象に、ニンテンドーswitchの商品ページをスクレイピングして売り切れかどうか判定するところまでできました。


今回はこの続きの
ビックカメラ.com(https://www.biccamera.com/bc/main/)の商品ページスクレイピング
・結果をスプレッドシートに書き出す

という部分について書いていきます。

ビックカメラ.comの商品ページ解析

前回の記事のヤマダウェブコムと同様に、ビックカメラ.comのニンテンドーswitchの商品ページを開いて、表示されるhtmlを確認していきます。

スイッチ本体の販売ページはhttps://www.biccamera.com/bc/item/7100370/なので、このページをブラウザで開いてhtmlを確認します。
f:id:J-back:20210321224506p:plain:w600


前回記事と同様に、購入可能かどうかを判定するため、「カートに入れる」ボタンあたりのhtmlを確認しておきましょう。
記事執筆時点ではニンテンドーswitch本体は品切れ(相変わらず人気ですね・・・!)なので、もう1つのパターンとして、
購入可能な商品のページのhtmlも確認します。

ニンテンドーswitch liteは在庫があり、購入可能だったので、switch liteの商品ページ(https://www.biccamera.com/bc/item/7135445/)を開き、htmlを確認します。
以下の画像のような感じですね。
f:id:J-back:20210321224534p:plain:w600



さて、上で挙げた2つのhtmlを比較すると、どちらも「カートに入れる」ボタンには

<div class="bcs_purchase">

という要素が存在し、その下の「ほしいものリストに追加」ボタンに

<p class="bcs_favBtnActive" id="wish">

という要素が存在しています。
さらに購入可能な状態のときはこれら2つの要素の間に

<button data-add-click="data-add-click" type="button" class="bcs_buyBtnActive BTN_CART_IN">
  <span>カートに入れる</span>
</button>

という要素が存在し、在庫がない場合には

<p class="bcs_buyBtn">カートに入れる</p>

という要素が存在していることが分かります。


したがって、上の要素を判定条件に入れて、以下のようなテストコードを書いてみます。

function testFunction() {
  let URL1 = "https://www.biccamera.com/bc/item/7100370/";
  let URL2 = "https://www.biccamera.com/bc/item/7135445/";
  
  
  let fromText = '<div class="bcs_purchase">';
  let toText = '<p class="bcs_favBtnActive" id="wish">';
  
  let html1 = UrlFetchApp.fetch(URL1).getContentText("Shift_JIS");
  let html2 = UrlFetchApp.fetch(URL2).getContentText("Shift_JIS");
  
  let state1 = Parser.data(html1)
  .from(fromText)
  .to(toText)
  .build();
  
  let state2 = Parser.data(html2)
  .from(fromText)
  .to(toText)
  .build();
  
  Logger.log(state1);
  Logger.log(state2);
  
  
  let available = "<button data-add-click=";
  let unavailable = '<p class="bcs_buyBtn">';
  
  if (state1.search(available) != -1){
    Logger.log("URL1:購入可能です");
  
  } else if (state1.search(unavailable) != -1){
    Logger.log("URL1:売り切れです");
  
  } else {
    Logger.log("URL1:判定できません");
  }
  
  if (state2.search(available) != -1){
    Logger.log("URL2:購入可能です");
  
  } else if (state2.search(unavailable) != -1){
    Logger.log("URL2:売り切れです");
  
  } else {
    Logger.log("URL2:判定できません");
  }
  
}


これを実行すると、下の画像のようなログが出力されます。
購入可否がうまく判定できていることが分かります。
f:id:J-back:20210321224616p:plain:w600


f:id:J-back:20210321224639p:plain:w600


スクレイピング用コード

ここからは、前回の記事で書いたヤマダウェブコムのスクレイピングコードと今回のビックカメラ.comのコードを合わせて、両方のサイトをチェックしてニンテンドーswitchが購入可能か判定するコードを書きます。

function myFunction() {
  let yamada_URL = "https://ymall.jp/kaden/1178230015/?q=Nintendo+switch";
  let bic_URL = "https://www.biccamera.com/bc/item/7100370/";
  
  let yamada_fromText = '<div class="side_button">';
  let yamada_toText = '</div>';
  
  let bic_fromText = '<div class="bcs_purchase">';
  let bic_toText = '<p class="bcs_favBtnActive" id="wish">';
  
  
  /* ヤマダウェブコム */
  let yamada_html = UrlFetchApp.fetch(yamada_URL).getContentText("UTF-8");
  
  let yamada_state = Parser.data(yamada_html)
  .from(yamada_fromText)
  .to(yamada_toText)
  .build();
  
  let yamada_available = "カートに入れる";
  let yamada_unavailable = "売り切れました";
  
  if (yamada_state.search(yamada_available) != -1){
    Logger.log("yamada:購入可能です");
  
  } else if (yamada_state.search(yamada_unavailable) != -1){
    Logger.log("yamada:売り切れです");
  
  } else {
    Logger.log("yamada:判定できません");
  }
  
  
  /* ビックカメラ.com */
  let bic_html = UrlFetchApp.fetch(bic_URL).getContentText("Shift_JIS");
  
  let bic_state = Parser.data(bic_html)
  .from(bic_fromText)
  .to(bic_toText)
  .build();
  
  let bic_available = "<button data-add-click=";
  let bic_unavailable = '<p class="bcs_buyBtn">';
  
  if (bic_state.search(bic_available) != -1){
    Logger.log("bic:購入可能です");
  
  } else if (bic_state.search(bic_unavailable) != -1){
    Logger.log("bic:売り切れです");
  
  } else {
    Logger.log("bic:判定できません");
  }
  
}


これを実行すると、以下のように2つのサイトに対する判定結果がそれぞれ出力されていますね。
f:id:J-back:20210321230730p:plain:w600


スプレッドシートへの結果書き込み

最後に、スクレイピングによって取得した情報から購入可否を判定した結果をスプレッドシートに書き込んでいく部分を実装します。


まずはスプレッドシートへのデータ書き込みについて、以下のテストコードを書いてみます。

function testFunction() {
 
var sheet = SpreadsheetApp.getActiveSheet();
 
var today = new Date();
 
var data = [[today, '○', '○']];
 
var lastRow = sheet.getLastRow();
var targetRow = lastRow + 1;
 
sheet.getRange(targetRow,1,1,3).setValues(data);
 
}
 

現在のスプレッドシートの最終行の次の行に「本日日付と○記号」を書き込むものです。


実行前のスプレッドシートの状態が以下のように、2021/3/23のデータまで書き込んである場合で試してみます。
f:id:J-back:20210324003127p:plain:w600


上記のテストコードを実行すると、以下画像のように、本日日付(3/24)の行のデータが書き込まれました。
f:id:J-back:20210324003309p:plain:w600


このようにスプレッドシートへのデータ書き込みの方法がわかったところで、スクレイピングのコードと合わせて最終的に以下のようなコードを作成します。

function myFunction() {
  let yamada_URL = "https://ymall.jp/kaden/1178230015/?q=Nintendo+switch";
  let bic_URL = "https://www.biccamera.com/bc/item/7100370/";
  
  let yamada_fromText = '<div class="side_button">';
  let yamada_toText = '</div>';
  
  let bic_fromText = '<div class="bcs_purchase">';
  let bic_toText = '<p class="bcs_favBtnActive" id="wish">';
  
  let sheet = SpreadsheetApp.getActiveSheet();
  
  let today = new Date();
  let data = [[today, '', '']];
  
  let lastRow = sheet.getLastRow();
  let targetRow = lastRow + 1;
  
  
  /* ヤマダウェブコム */
  let yamada_html = UrlFetchApp.fetch(yamada_URL).getContentText("UTF-8");
  
  let yamada_state = Parser.data(yamada_html)
  .from(yamada_fromText)
  .to(yamada_toText)
  .build();
  
  let yamada_available = "カートに入れる";
  let yamada_unavailable = "売り切れました";
  
  if (yamada_state.search(yamada_available) != -1){
    data[0][1] = '○'
  
  } else if (yamada_state.search(yamada_unavailable) != -1){
    data[0][1] = '×'
  
  } else {
    data[0][1] = '?'
  }
    
  
  /* ビックカメラ.com */
  let bic_html = UrlFetchApp.fetch(bic_URL).getContentText("Shift_JIS");
  
  let bic_state = Parser.data(bic_html)
  .from(bic_fromText)
  .to(bic_toText)
  .build();
  
  let bic_available = "<button data-add-click=";
  let bic_unavailable = '<p class="bcs_buyBtn">';
  
  if (bic_state.search(bic_available) != -1){
    data[0][2] = '○'
  
  } else if (bic_state.search(bic_unavailable) != -1){
    data[0][2] = '×'
  
  } else {
    data[0][2] = '?'
  }
  
  /* スプレッドシートへ結果書き込み */
  sheet.getRange(targetRow,1,1,3).setValues(data);
  
}


上記プログラムを実行すると、スクレイピングを実施後、ニンテンドーswitchが購入可能だった場合は「○」、売り切れだった場合は「×」、Webページの問題で判定できなかった場合などは「?」をスプレッドシートに入力するという動作をします。


実行結果は以下の画像のような感じです。
ニンテンドーswitchはずっと売り切れなので、スプレッドシートが「×」ばかりで見た目的にあまりおもしろくないですね・・・
f:id:J-back:20210324010125p:plain:w600





今回は以上です。最後まで読んでいただきありがとうございました。