【初心者向け 解説編】GASを使ってAmazonのデータをスクレイピングしよう!

2022年5月24日

Google Apps Script(GAS)Parserライブラリを使って、Amazonの商品タイトルをスプレッドシートに取り込む方法を初心者の方に向けてお送りする記事、解説編でございます。

前回は導入編ということで、Apps Script画面の表示とParserライブラリの導入、そして実際に商品タイトルをスプレッドシートに取り込むまでのサンプルコードをまとめました。

↑導入編の記事はこちら


今回はサンプルコードで一体どんなことが起きているのかをjavascriptをまったく知らない方に向けて解説していきます。

ひとつひとつ理解していくことで、少しずつでも自分でできることの幅が広がっていきます

プログラミングってちょっと面白いなと思っていただけたら嬉しいです。それではどうぞ。

(長文なので、休みながら読んでくださいね。)



前回のサンプルコード

前回書いたサンプルコードはこちらです。

function myFunction(){
  let response = UrlFetchApp.fetch('https://www.amazon.co.jp/(省略)');
  // UrlFetchApp.fetchのカッコ内にはデータを取りたい検索結果ページのURLを入れてください

  let fromText = '<span class="a-size-base-plus a-color-base a-text-normal">';
  let toText = '</span>';

  let titleList = Parser
  .data(response.getContentText())
  .from(fromText)
  .to(toText)
  .iterate();

  let sheet = SpreadsheetApp.getActiveSheet();

  for(let i=0; i<titleList.length; i++){
    sheet.getRange(i + 2, 1).setValue(titleList[i]);
  }
}

基本ルールとして、javascriptコードではないただの文字列(サイトのURLなど)は『’』(シングルクォーテーション)で囲みます。

また、行の終わりには;(セミコロン)を付けて「ここでこの行は終わりだよ」というアピールをしておきます。


では上から順にひとつひとつ見ていきましょう。

と、その前に変数宣言について簡単に説明しますね。


変数宣言、『let』

  let response = UrlFetchApp.fetch('https://www.amazon.co.jp/(省略)');
  
  let fromText = '<span class="a-size-base-plus a-color-base a-text-normal">';

  let toText = '</span>';

上記3つのどれもがletという言葉から始まっていますね。

これは変数宣言と言って、それぞれ空き箱に名前を付けてその中にモノを入れるという作業をおこなっています。

上の画像のようにurlという箱を作ってURLを入れたり、fruitという箱を作ってappleを入れたり。

箱の名前も、入れるものも(ある程度)自由です。

箱に入れておけば持ち運びがしやすいのでとても便利です。

  let          fruit            =       'apple';
箱作るぞ!  fruitという名前の!  そして入れよう  appleを!

これで度々出てくるletの謎は解明されましたね。箱を作って梱包していたわけです。

そしてこの『箱』のことをプログラミングの世界では変数と呼んでいます。

中身を変えられる数、変数。

letの「箱作るぞ!」というセリフは「変数作るぞ!」と同じ意味です。だから、変数宣言


UrlFetchApp.fetch(切り抜くページの指定)

let response = UrlFetchApp.fetch('https://www.amazon.co.jp/(省略)');

さて、最初の行からいきなり小難しい文字が飛び出してきました。UrlFetchApp.fetch

これはfetchのあとの()内に書いたURLにアクセスして、返ってきた結果をresponseという名前の箱に入れるという動作になります。

今回はAmazonにて「キーボード」で検索した結果のページを要求(リクエスト)しました。

Amazonさんはページの内容を返信(レスポンス)してきます。

そのレスポンスをresponse変数に梱包しています。

これは概念的にも難しいところなので、今はUrlFetchApp.fetchという魔法ととらえていただいて大丈夫です。

魔法のおかげでresponseという名前の箱に検索結果を入れて自由に持ち運ぶことができるようになりましたね。


fromText, toText(切り抜く場所の指定)

  let fromText = '<span class="a-size-base-plus a-color-base a-text-normal">';
  let toText = '</span>';

この2行で切り抜く場所を指定しています。


どういう原理かというと、まず基本的にwebページはhtmlという言葉で記述されています。

Amazonの場合普段見えないんですが、実は商品タイトルは<span>というhtmlタグに囲まれているんですよ。


実際に確認してみましょう。

chromeでAmazonを開いて、WindowsならF12キー、macならoption + command + iキーを押してみてください。すると…

右側に怪しい画面が出てきましたね。

これは開発者ツールといって、現在読んでいるページがどんなhtmlで書かれているのかを表示してくれます。


小さくて見にくいんですが、開発者ツールの左上にある矢印ボタンをクリックしてください。(クリックすると矢印ボタンが青くなります)


矢印ボタンが青い状態のまま、Amazonの商品タイトルをクリックしてください。(カーソルを商品タイトルに当てると青い四角が表示されるので、そこでクリック)



すると、開発者ツール側では今クリックした場所のhtmlを瞬時にハイライトしてくれます。

<span class="a-size-base-plus a-color-base a-text-normal">ロジクール ワイヤレス…</span>

と書かれていますね。

タイトルが<span>タグで囲まれていることが実際に確認できました。


Parserは切り抜きたい文字の前(from)後ろ(to)にある文字を消す働きをしてくれます。

<span class="a-size-base-plus a-color-base a-text-normal">ロジクール ワイヤレス…</span>


コードをもう一度見てみましょう。

  let fromText = '<span class="a-size-base-plus a-color-base a-text-normal">';
  let toText = '</span>';

あとでParserにお願いする時のために、前と後ろの文字をそれぞれfromTexttoText変数に入れているところということがおわかりいただけたでしょうか。

ちなみに商品タイトルはすべて上記のspanタグに囲まれているので、他の商品タイトルにも流用できます。


<span class="a-size-base-plus a-color-base a-text-normal">ロジクール ワイヤレス…</span>

<span class="a-size-base-plus a-color-base a-text-normal">ロジクール アドバンスド…</span>


fromtoが消えるから、結果として

ロジクール ワイヤレス…

ロジクール アドバンスド…

こうしてタイトルだけが残るんですね。


あとはParserにおまかせ!

  let titleList = Parser
  .data(response.getContentText())
  .from(fromText)
  .to(toText)
  .iterate();

さて、秘密道具Parserの出番です。

Parser君は、『どのページの』『どの部分を切り抜くか』という指示をしてあげることで仕事を始めます。

今までの段階で箱詰めしてきたresponse変数とfromText、toText変数がここで使われます。


2行目のresponse.getContentText()ですが、response変数には先ほどUrlFetchApp.fetchでAmazonから送ってもらったレスポンスが入っています。

このレスポンスには必要のないデータもまとめて入っているので、その中から今回使う文字列をgetContentText()という魔法で抜き出しています。


.data(response.getContentText())や.from(fromText)など、ドットから始まっている部分はParser君が知っている言語で会話している様子です。

.iterate();は該当するものがあるだけ全部お願いする命令です。

(一か所だけ欲しい場合は.iterate();の代わりに.build();という命令にします。)

Parser    .data()    .from()   .to()
Parserです。どのページの    どこと     どこの間が 欲しいですか? ()の中に書いてくださいね。
Parser   .data(response.getContentText()) .from(fromText)  .to(toText)      .iterate();
Parser君、   お願いしたいページはここで        ここと       ここの間を切り取ってね  全部お願い。

こうしてParser君は命令を理解し、商品タイトルをすべて切り抜きます。


もう一度コードを見てみましょう。

  let titleList = Parser
  .data(response.getContentText())
  .from(fromText)
  .to(toText)
  .iterate();

実は1行目で変数宣言しています。

切り抜かれた商品タイトルを全部まとめてtitleList変数に梱包しています。

のちほどひとつずつ取り出してスプレッドシートに渡すので、持ち運びできるようにしておきます。



使うスプレッドシートの指定

let sheet = SpreadsheetApp.getActiveSheet();

スプレッドシートに書き込むためにはApps Script側で一度スプレッドシートを呼び出しておかないといけません。

今回はスプレッドシートからApps Script画面を開きました。

つまり既にふたつは紐づいているのでSpreadsheetApp.getActiveSheet();という魔法の言葉だけで呼び出し完了です。

魔法によって呼び出されたスプレッドシートのデータをsheet変数に格納しておきます。


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

  for(let i=0; i<titleList.length; i++){
    sheet.getRange(i + 2, 1).setValue(titleList[i]);
  }

さぁ、いよいよ大詰めです。

sheet.getRange(i + 2, 1).setValue(titleList[i]);の説明をしますが、ここは複雑なのでひとつずつ見ていきましょう。


書き込むセルの指定方法

スプレッドシートのどのセルに書き込むかは.getRange()で指定します。

.getRange(行、 列)となります。列はアルファベットではなく、A列なら1、B列なら2…と数字で指定します。

A3のセルだったら.getRange(3, 1)

C5のセルだったら.getRange(5, 3)となります。


書き込む内容の指定方法

書き込む内容は.setValue()で指定します。()の中身が実際に書き込まれる内容です。

.setValue('テスト’)とすればテストという文字がスプレッドシートに書き込まれるわけですね。


titleListから商品タイトルを取り出す方法

Parser君のおかげでtitleList変数にすべての商品タイトルがまとめて入っているわけですが、実は自動で番号が振られています

0番 ロジクール ワイヤレス…

1番 ロジクール アドバンスド…

2番 ロジクール MX KEYS…

このように0番から始まる番号と一緒に商品タイトルが入っているんです。

番号を指定することで対応した商品タイトルの文字を取り出すことができます。

titleList[0]とすると ロジクール ワイヤレス…が取得できます。

titleList[2]であれば ロジクール MX KEYS…が出てきます。

これは配列と呼ばれます。詳しく知りたい方は『javascript 配列』なんかで検索してみてくださいね。


ここまでをまとめると…

getRangeでセル指定setValueで内容指定、そしてtitleListからのタイトルの取り出し方を合わせると次のようになります。

sheet     .getRange(1, 1) .setValue(titleList[0]);
シートさん、   A1のセルに   ロジクール ワイヤレス… を書き込んでください

sheet     .getRange(2, 1) .setValue(titleList[1]);
シートさん、   A2のセルに   ロジクール アドバンスド… を書き込んでください

これを商品タイトルの個数分書けばスプレッドシートへの取り込みは完了です。

…そんな面倒なことはやってられませんよね?

そこでfor文を使います。

for文で処理を繰り返す

for文は繰り返し処理をおこなう際のプログラミング技です。

titleList変数には商品タイトルが番号と一緒に全部格納されているのは上述の通りです。

いくつ入っているのかはtitleList.lengthでわかります。

今回は48個の商品タイトルが入っていました。番号としては0番から47番まで割り振られています。

  for(let i=0;      i<titleList.length;        i++){ ここに書かれた処理を繰り返す }
      0番目から始めて  iが47番目になるまで。  処理が終わったらiを1ずつ増やす

上述のgetRangesetValueをfor文の中で使うと次のようになります。

sheet      .getRange(i + 2, 1)      .setValue(titleList[i])
シートさん、  i + 2行目、Aの列に   i番目の商品タイトルを書き込んでください

このfor文はiが0から始まって、iが47になるまで処理を繰り返すんでした。つまり…

sheet.getRange(0 + 2, 1).setValue(titleList[0]); for文1回目 セルA2
sheet.getRange(1 + 2, 1).setValue(titleList[1]); for文2回目 セルA3
sheet.getRange(2 + 2, 1).setValue(titleList[2]); for文3回目 セルA4
…
sheet.getRange(47 + 2, 1).setValue(titleList[47]); for文47回目 セル49

A2からA49までのセルに タイトルを0番から順番に書き込んでいってくれるわけですね!

※今回A1には「商品タイトル」という見出しを入れているので書き込みをA2からにしています。


もう一度サンプルコードを見てみましょう。

  for(let i=0; i<titleList.length; i++){
    sheet.getRange(i + 2, 1).setValue(titleList[i]);
  }

どうですか?ヒントなしでも何が起きているか読み解けるでしょうか?



まとめ

function myFunction(){
  let response = UrlFetchApp.fetch('https://www.amazon.co.jp/(省略)');
  // response変数にAmazonからのレスポンスを格納

  let fromText = '<span class="a-size-base-plus a-color-base a-text-normal">';
  let toText = '</span>';
  // 商品タイトルを囲んでいるタグをfromText,toText変数に格納

  let titleList = Parser
  .data(response.getContentText()) // レスポンスから必要な文字列を取り出し
  .from(fromText)           // <span ~>と
  .to(toText)                     // </span>の間を切り取る
  .iterate();                      // あるだけやってね

  let sheet = SpreadsheetApp.getActiveSheet();
  // スプレッドシートの読み込み

  for(let i=0; i<titleList.length; i++){
    sheet.getRange(i + 2, 1).setValue(titleList[i]); // 0番から最後までを全部書き込み
  }
}

以上になります。

かなりの長文記事になってしまいました。お疲れ様でした。

ここまで読んでくださった方、本当にありがとうございます。

ちょっとでも理解の助けになれば幸いです。


参考にさせていただいたこちらの記事では価格の取得方法も書かれていますので、是非ご一読ください。

今回出てきたfor文配列などはjavascriptの基礎的な要素なので、プログラミングを続けていく上では必修です。

Progateや参考書などを活用して、学んでみてくださいね。


Google Apps Scriptを学びたい方はこちらの参考書。


javascriptの基礎から学びたい方はこちらの参考書がイチオシです!

【追記 2022/03/17】

スプレッドシートにGASを実行するボタンを作る方法を記事にしました。

いちいちGASのページで実行するという手間が省けますので、ぜひ試してみてくださいね。



この記事が面白かった、役に立ったという方はバナーのクリックをお願いします!

ブログランキング・にほんブログ村へ

励みになります😉