11
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GASを使ったスクレイピングのやり方

Last updated at Posted at 2023-12-02

はじめに

この記事は「Ateam LifeDesign Advent Calendar 2023」で完走賞を狙って25記事書いているうちの3日目の記事です。今年も完走目指して頑張るぞ!

GASを使ったスクレイピング

今私が見てる部署では比較的スクレイピングを使う人が多いので参考になるかもな?と思い、実践編の最初にスクレイピングを持ってきました。それでは早速見ていきましょう。

作るもの

こんなシートを用意してA列に入っているURLにアクセスし、取ってきた情報で必要なものをB列に入れていきます。

スクリーンショット 2023-11-20 11.15.09.png

今回スクレイピングするのは弊社が運営してる結婚式場の紹介サービスであるハナユメというサイトです。結婚式場の詳細が書かれたページのなかから赤枠で囲われている情報を取得してきたいと思います。

スクリーンショット 2023-11-20 11.17.15.png

準備

今回はCherrioというライブラリを利用したスクレイピングの方法をご紹介します。

まず「ライブラリ」をクリックしたあと、スクリプトIDに

1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0

を入力し、最新のバージョンのCheerioを追加します。

スクリーンショット 2023-11-20 9.38.14.png

Cherrioの使い方はこちらに詳しく書いてありますがjQueryライクに要素を取ってくることが出来ます。こんな感じで簡単にコンテンツを取ってこれます。

function getContent_(url) {
    return UrlFetchApp.fetch(url).getContentText()
}

wikipediaのメインページを取得する方法。

  const content = getContent_('https://en.wikipedia.org');
  const $ = Cheerio.load(content);
  Logger.log($('#mp-right').text());

これでCherrioライブラリが使用できるようになったので、ここからは実際どんなコードを書いて実装していくのか順を追って説明していきます。

GASを書いていく

URLが入ってるA列のセルの中身を取得

  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet  = spreadsheet.getActiveSheet();
  var lastRow = sheet.getLastRow();
  var range  = sheet.getRange(1,1, lastRow);
  var values = range.getValues().flat().filter(String).map(String);

ここは主に昨日の記事でやった内容です。sheet.getLastRow()の部分が新しく出てきていますが、この関数はそのシートでデータの入ってる最終行数を返す関数です。サンプルだとURLが5つはいってるのでsheet.getRange(1,1,5)としても動作しますが、この書き方だとURLをどんどん追加していったときに都度プログラム側を変更する必要があるのであまり美しくないですよね。なので最終行を取ってこれる関数を使って指定をするようにしています。

range.getValues().flat().filter(String).map(String)の部分は二次元配列をその後の処理で扱いやすいように一次元配列にしています。今回の場合入力されてるのは文字列型なのでStringを指定していますが、数値型であればNumberを指定しましょう。

取れてきたURLを1つずつ順番にスクレイピングする

  for(let i = 0; i < values.length; i++) {
    var url = values[i];
    if (url) {
      var content = UrlFetchApp.fetch(url).getContentText();
      var $ = Cheerio.load(content);
      var targetText = $('.hallStatus').text();
      setInfo[i] = [];
      setInfo[i].unshift(targetText.replace(/[\r\n]+/g,""));
      Utilities.sleep(3000);      
    }
  } 

A列から取ってきたURLのリストは先程の手順で一次元の配列になっているので今回はforで1つずつ見ていきます。URLが空の場合にスクレイピングの処理を通そうとするとエラーが出てしまうので空欄があったときのことを考慮してifでURLがセルに記載されている場合のみスクレイピング処理を実行するようにします。実際のスクレイピングは上述のサンプルの通りです。なんともめちゃくちゃ簡単・・・感動・・・!
スクリーンショット 2023-11-20 22.01.01.png
今回取ってきたかったところにはhallStatusというclassが振られていたので.hallStatusという指定をしています。もしこれがid="hallStatus"であれば$('#hallStatus').text()と指定すればOK。もっと細かな指定もできますが、ここでは割愛。jQueryのDOMの指定方法と同じなのでjQuery DOM操作あれこれがとても参考になると思います。

そのままtargetTextを入れていたのでが改行コードが含まれていたため.replace(/[\r\n]+/g,"")を追加して改行コードを空文字で置換しています。

そしてスクレイピングはお行儀よくしないとなのでUtilities.sleep(3000);で3秒間処理を止めています。大量アタックはサイト運営者にご迷惑おかけしちゃうからね。Utilities.sleep(ミリ秒)という指定の仕方をしてください。

スクレイピングして得られた結果を書き込む

  var outputRange = sheet.getRange(1, 2, lastRow);
  outputRange.setValues(setInfo);

ここでは取得してきたデータを二次元配列で保持しておいてそれをsetValuesをつかって書き込んでいます。これだけのデータ量であればfor回している中で1セルずつに対してsetValueしても、最後にまとめてsetValuesしても速度はそこまで変わらないのですが、データ行数が数百レベルになってくると実行結果に明らかな差が出てきます。
GASには1度の処理での実行時間に上限があるのでなるべくまとめてデータをとりだす、まとめてデータを書き込むを身に着けておいたほうがいいので今回はまとめて書き込む方法でサンプルを作成しました。

それではここまでをまとめたものと実際の実行結果を見てみましょう!

完成品がこちら

GASのコード

function myFunction() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet  = spreadsheet.getActiveSheet();
  var lastRow = sheet.getLastRow();
  var range  = sheet.getRange(1,1, lastRow);
  var values = range.getValues().flat().filter(String).map(String);
  var setInfo = [];

  for(let i = 0; i < values.length; i++) {
    var url = values[i];
    if (url) {
      var content = UrlFetchApp.fetch(url).getContentText();
      var $ = Cheerio.load(content);
      var targetText = $('.hallStatus').text();
      setInfo[i] = [];
      setInfo[i].unshift(targetText.replace(/[\r\n]+/g,""));
      Utilities.sleep(3000);      
    }
  }  

  var outputRange = sheet.getRange(1, 2, lastRow);
  outputRange.setValues(setInfo);
}

実行結果

無事に赤枠で囲っていた部分を取得してB列に書き込めていますね。

スクリーンショット 2023-11-20 21.45.27.png

最後に

今回はCheerioライブラリを使ってGASでスクレイピングするやりかったについてまとめました。思ったより簡単にできましたね!明日は弊社でもよく使われそうなSlack連携について書いていこうと思います。
くれぐれもスクレイピングは迷惑のない範囲で使いましょうね!

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?