GASでスクレイピングを作ってみた

GAS業務効率

スクレイピングとはWebページから情報を収集し、解析・加工などの処理を行うことで、Google Apps Script(GAS)で自動化することができます。

何のためにスクレイピングをする?

例えば、膨大な店舗情報があるページから「会社名」と「電話番号」だけを抜き取って営業先リストにしたり、競合サイトのエリア別の掲載数を調査して分析したりすることが可能です。

クロール対象一覧を作成する

まずは、クロール対象となるURLのリスト作成する必要があります。下記にサンプルのスプレッドシートを用意したので、まずは開いて内容を確認してください。

各項目の意味は次の通りです。A~F列は事前に入力しておく必要がありますが、G~I列はGASの出力値になるため、入力不要です。

項目名解説
A列KEY分類後で分類や集計しやすいように分類しておく名前です。省略してもOKです。
B列クロールURLWEBページのURLをリスト化しておきます。
C列直前のソースコードHTMLソースコードから「抽出したい情報」の直前のソースコードを記入してください。
D列直後のソースコードHTMLソースコードから「抽出したい情報」の直後のソースコードを記入してください。
E列文字コードHTMLソースコードの文字コードを入力してください。
F列クロール間隔(ms)B列のURLをクロールする間隔をミリ秒で入力してください。
G列エラー入力不要です。エラーを出力します。
H列抽出文字列入力不要です。スクレイピングで抽出した文字列を出力します。
I列チェック日入力不要です。スクレイピングした日付を出力します。

なお、シート名はサンプルの通りに、「_setting」としておいてください。

直前&直後のソースコードを確認する

仮に、「SUUMOの賃貸物件数を毎日確認したい」とします。

対象ページで右クリックして「ページのソース」を表示してください。ソースコードの中を抽出したい文字列で検索します(windowsなら『Ctrl+F』で検索できます)。

つまり、今回は「7,241,500」という数値を抽出したいので、その前後のソースコードをシートのC列とD列に入力します。

上記の場合は、<dd>賃貸物件(<span>が直前のソースコードで、</span>件が直後のソースコードになります。

文字コードを確認する

同様に文字コードもソースコードをcharsetという文字を検索すると見つかります。次の図だとUTF-8に指定されているので、E列にUTF-8と記入します。

スクレイピングの間隔を決める

スクレイピングはやろうと思えば1秒間に100回アクセスなんてこともできるので、対象サイトのサーバーに負荷がかかります。お作法として相手のサーバーに負荷がかからないように、1ページあたり1~3秒程度で移動するように間隔をミリ秒(1秒=1,000ミリ秒)で指定しておきましょう。

Google Apps Script(GAS)を書く

スプレッドシートに戻って、「ツール」から「スクリプトエディタ」を選択し、エディアを開きましょう!

次のコードを書いてみましょう。コピペで貼り付けてもかまいません。

/*------------------------------------------------------------
メニュー追加
------------------------------------------------------------*/
function onOpen(event){
  var menuitems = [
    {name:'クロール開始', functionName:'startCrawl'},
  ];
  var sheet = SpreadsheetApp.getActiveSpreadsheet();
  sheet.addMenu('GASスクリプト実行', menuitems);
}
/*------------------------------------------------------------
シートをクロールしてデータ収集
------------------------------------------------------------*/
function startCrawl() {
  // シート定義
  var book = SpreadsheetApp.getActiveSpreadsheet();
  var sheetData = book.getSheetByName("_setting");
  
  // シート列の定義
  var colURL = 2;
  var colStartTag = 3;
  var colEndTag = 4;
  var colCharset = 5;
  var colTimer = 6;
  var colError = 7;
  var colFindTxt = 8;
  var colDate = 9;

  // 開始行
  var rowStartData = 2;
  var rowEndData = sheetData.getDataRange().getLastRow();
  
  // リクエストヘッダー
  var options = {
    "method" : "GET",
    "headers" : {
      "user-agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.125"
    },
    /* ログイン時使用
    "payload": {
      "user_id" : "userid", 
      "password" : "pass"
    },
    */
    "muteHttpExceptions" : true
  }; 
  
  var today = new Date();
  
  // 取得
  for (var i = rowStartData; i <= rowEndData; i += 1) {
    
    // クロールURL生成
    var url = sheetData.getRange(i, colURL).getValue();
    var charset = sheetData.getRange(i, colCharset).getValue();
    var response = UrlFetchApp.fetch(url, options);
    var html = response.getContentText(charset);
    Logger.log(html);
    
    // 部分取得
    var searchSTag = sheetData.getRange(i, colStartTag).getValue();
    var searchETag = sheetData.getRange(i, colEndTag).getValue();
    var index = html.indexOf(searchSTag) // 「開始タグ」が最初に発見された位置
    if (index !== -1) {
      var html = html.substring(index + searchSTag.length); // 「開始タグ」より前を削除
      var index = html.indexOf(searchETag); // 「閉じタグ」が最初に発見された位置
      if (index !== -1) {
        sheetData.getRange(i, colFindTxt).setValue(html.substring(0, index));
        sheetData.getRange(i, colError).setValue("");
        sheetData.getRange(i, colDate).setValue(today);
      }else{
        sheetData.getRange(i, colFindTxt).setValue("");
        sheetData.getRange(i, colError).setValue("閉じタグが見つかりません");
        sheetData.getRange(i, colDate).setValue(today);
      }
    }else{
        sheetData.getRange(i, colFindTxt).setValue("");
        sheetData.getRange(i, colError).setValue("開始タグが見つかりません");
        sheetData.getRange(i, colDate).setValue(today);
    }
    
    // クロール間隔
    var timer = sheetData.getRange(i, colTimer).getValue()*1;
    Utilities.sleep(timer);
  }
}

保存して、スクリプトエディタを閉じます。

GASを実行してみよう

スプレッドシートに戻ったらページを更新してください。次のメニューが新たに追加されているハズです。「クロール開始」を選択すると、スクレイピングが実行されます。

タイマーで自動収集も可能

以前紹介したトリガーを使って、毎日、週1回、月1回などスクレイピングを自動で行うシステムが作れます。ただし、制限もあるため注意が必要です。

スクレイピングに失敗するケース

筆者が試した感じだと、稀にスクレイピングに失敗するサイトがありました。調べてみると取得したHTMLソースコードの中身が白紙になっていたのです。いわゆるスクレイピング対策がしてありました。

おそらくサイト側でユーザーエージェントをチェックしているのでしょう。GASのユーザーエージェントだと、白紙を返すようにしているのだと思います。UserAgentを変更してfetch(データなどを読み出すこと)できないかと思い、下記のスクリプトを追加しているのですが、やはり白紙のままでした。

  // リクエストヘッダー
  var options = {
    "method" : "GET",
    "headers" : {
      "user-agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.125"
    },
    /* ログイン時使用
    "payload": {
      "user_id" : "userid", 
      "password" : "pass"
    },
    */
    "muteHttpExceptions" : true
  };

タイトルとURLをコピーしました