members

members

【スプレで完結】 Webスクレイピングで行うページチェックの自動化

Tweet

【スプレで完結】 Webスクレイピングで行う ページチェックの自動化

はじめまして。エンジニアの関口です。
大規模なリニューアルや、数千ページの運用を行なっていくと、個々のページでどんなタイトル・ディスクリプション・h1が設定されているのか、管理するだけで時間がとられてしまいます。サイトの更新頻度が高いとなおさら大変です。

そんな面倒な作業はスプレッドシートとGAS(Google App Script)を使って自動化してしまいましょう。コーディング面に加えて、手法となるスクレイピングとその注意点を中心に、解説していきます。
※「GASってなに!?」という方はこちらを先に読んでもらえると、理解がはかどります。

参考)【Google Apps Script入門】Google Apps Scriptとは?
参考)【Google Apps Script入門】セルの取得・変更をする

 

目次

 

今回の目的と手段の整理

 

このツールで目指すこと

  • 入力したURL一覧からスクレイピングによって、個別のmeta情報などを取得し、スプレッドシート上に表示させること
  • ツールの実行では、コーディングがわからない人でも作業できること

 

GASで行うメリット

GASは、googleアカウントとブラウザさえ持っていれば、動作環境を整えることができます。また、市販のツールを利用するための面倒な社内での調整・セキュリティチェックの負担も軽減できます。

 

スクレイピングについて

スクレイピングとは?

データの抽出・整形の行為を指します。
その中でWebスクレイピングは、Web上の情報を取得することを指しており、クローラーと呼ばれるプログラムによる機械的な取得が主です。
行うには市販のツールを利用したり、pythonなどのプログラミング言語で自作プログラムを作成したりします。

Webスクレイピングを行う際に守ること

スクレイピングを行う際は主に著作権・robots.txtの二種類に注意します。

著作権

Web上に公開されているものは、基本的に著作権が発生しており、法令が定める、制限下での利用を行う必要があります。

著作権法では,一定の「例外的」な場合に著作権等を制限して,著作権者等に許諾を得ることなく利用できることを定めています(第30条〜第47条の8)
参考)文化庁

スクレイピングでは主に、「私的使用のための複製(第30条)」「情報解析のための複製等」にあたる部分での利用になります。
チェック作業の自動化などではあまり問題視することはないかもしれませんが、スクレイピングを応用したサービス制作・公開などを行う場合は、平成30年の改訂で、細かい定義がされたようなので、注意する必要があります。
参考)弁護士が解説 “平成30年改正著作権法”がビジネスに与える「衝撃」(ITmedia)

robots.txt

robots.txtとは、クローラーに対し、サイトのアクセス制限を明示的に知らせる目的で配置するファイルです。
参考)robots.txt の概要
外部サイトのスクレイピングを行う場合などは特に、このファイルや、各サイトの利用規約を必ず確認するようにしましょう。例えば、Facebook社は、robots.txtに下記を記載しています。

Collection of data on Facebook through automated means is prohibited unless you have express written permission from Facebook and may only  beconducted for the limited purpose contained in said permission.
自動化された手段によるFacebookでのデータの収集は、Facebookからの書面による明示的な許可がない限り禁止されており、上記に含まれる限られた目的でのみ実行できます
訳:筆者

また、Webスクレイピングは、機械的に複数のファイルに対して連続して行うことができます。そのため、サーバの負荷にもなり得ます。マナーとして、アクセスとアクセスの間に1秒程度、間を設けるようにしましょう。
自社サイトのチェック用であれば、社員のみに解放されているテスト環境などが存在している場合もあると思いますので、本番サーバに影響しないところでツールを回せると安心です。

 

ツールを制作する

では実際にツールを制作していきましょう。

使用するもの

  • スプレッドシート
  • ライブラリ「cheerio」
  • google アカウント

 

1 ライブラリのインストール

まずは新規スプレッドシートを作成して、ライブラリを有効にしましょう。

Cheerio ID
1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0
引用:https://github.com/tani/cheeriogs

方法は下記が画像付きで詳しいです。
参考)【GAS】Cheerioライブラリを使ってWebスクレイピング

2 コーディング

上記の記事を参考にしつつ、簡易的なものをコーディングしました。
できるだけ、初期設定に編集必須な値をおいています。


function checker(){
  /*
  ========================================
  初期設定
  ========================================
  */
  const sheet = SpreadsheetApp.getActiveSheet(),
        startRow = 2,//情報を置くセルの一番左上の列番号(A = 1...)
        startCol = 6,//情報を置くセルの一番左上の行番号(1 = 1...)
        URLListRow = startRow - 1,//URLリストの配置した列番号
        authInfo = {
          userName : '',//basic認証を行う場合のユーザーネーム
          password : ''//basic認証を行う場合のパスワード
        },
        /**
         * 取得するメタ情報
         * outName => 取得する情報の名前 好きに設定(空は不可)
         * name    => name or property属性を設定
         * prop    => 上記nameで設定した属性の値を設定
        */
        metaInfo = [
          {
            outName:'keywords',
            name:'name',
            prop:'keywords',
          },
          {
            outName:'desc',
            name:'name',
            prop:'description',
          },
          {
            outName:'og_title',
            name:'property',
            prop:'og:title',
          },
          {
            outName:'og_desc',
            name:'property',
            prop:'og:description',
          },
          {
            outName:'og_url',
            name:'property',
            prop:'og:url',
          },
        ]
 
 
  /*
  ========================================
  以下 script
  ========================================
  */
  
  // clear cell
  for (let i = startRow; i <= sheet.getLastColumn(); i++){
    const dataRange = sheet.getRange(startCol,i,sheet.getLastRow());
    dataRange.clearContent();
  }
 
  // create url data
  const urlData = sheet.getRange(startCol,URLListRow,sheet.getLastRow() - 1).getValues();
  let ary = '';
  for (var a = 0; a<urlData.length;a++){
    if(urlData[a][0]){
      ary = ary + String(urlData[a][0]) + ','
    }
  }
  ary = ary.split(',');
  ary.pop();
 
 
  // header option
  const options = {
    method: "GET",
    headers: {"Authorization" : "Basic " + Utilities.base64Encode(authInfo.userName + ":" + authInfo.password)},
    "muteHttpExceptions" : true,
    "validateHttpsCertificates" : false,
    "followRedirects" : false
  }
  let result = [];
 
  // get html data
  for(var i = 0; i < ary.length; i++){ 
  try { 
   let obj = Object.assign({});
   let r = Object.assign({});
   let resultURL = ary[i];
   const res = UrlFetchApp.fetch(resultURL,options);
      const content = res.getContentText()
      const $ = Cheerio.load(content);
      obj.title = $('title').text();
      obj.h1 = $('h1').text();
      metaInfo.forEach((v)=>{
        const reg = new RegExp(v.prop,'g');
        if(content.match(reg)){
          obj[v.outName] = $(`meta[${v.name}="${v.prop}"]`).attr("content");
        }else{
          obj[v.outName] = false;
        }
      })
      r.props = Object.assign({},obj);
 
      result.push(r);
 
      obj = null;
      r = null;
      //sleep 1秒
      Utilities.sleep(1000);
    } catch(e) {
      // 例外エラー処理
      console.log('Error:'+e);
    }
  }
 
  // draw cell
  result.forEach((d,r)=>{
    Object.keys(d.props).forEach((k,i)=>{
      const row = startCol + r;
      const col = startRow + i;
      sheet.getRange(row, col).setValue(d.props[k]);
    })
  })
}

 

初期設定(7行目~48行目)

metaInfoという変数のみ、複雑なため、解説します。
html内のmeta情報というのは、2種類の属性を持っています。



meta content="メンバーズは、デジタルビジネス支援を通じ……" name="description" 
meta content="https://www.members.co.jp/" property="og:url"

例のように、「content」は両方に入っていますが、「name」「property」はどちらか一方にのみ入っています。
そのため、まず「name」で属性がどちらなのかを定義し、その中で実際に取得する種別を「prop」で定義しています。

スクリプト処理部分(56行目~)

おおまかに下記の流れです。

  1. セルを初期化
  2. URL一覧をシートから取得
  3. 2で取得できたURL分、データをスクレイピングする
  4. シートに値を反映

 

3 動作テスト

では、実際に動作させてみましょう。
テストにはメンバーズのWebサイトを使用しました。robots.txtはこちら。

完成イメージ

GASのコーディング画面上でも関数は実行できますが、ページにボタンを設置して、関数名を割り当てることで、コーディング画面をいちいち開かなくても、実行できます。

  1. 挿入→図形描画で適当な図形を描く
  2. シート内に配置後、右クリックで図形を選択し、右上3点リーダからスクリプト割り当てを選択
  3. 動作させる関数名を入力(上記コードなら「checker」と入力)
※最初の実行のみ、GASとスプレッドシート、ライブラリを紐づけるため、アカウント認証が発生します。

 

GASの注意点

GASには実行時間や回数に制限が存在します。
本記事にかかわるものは下記の通りです。
参考)Quotas for Google Services(developers.google.com)
翻訳:筆者

項目 制限
スクリプトの実行時間 6分 / 1回
URLフェッチ※の呼び出し 20,000 / 1日
URLフェッチ※の応答サイズ 50MB / 1回
URLフェッチ※のURLサイズ 2KB / 1回

フェッチ……URLにアクセスし、情報を取得する行為。本記事ではHTTP通信によるものを指し、ブラウザのアドレスバーにURLを入力してサーバからHTMLなどのファイルを取得する行為と同等。

 

上記の制限を超えた場合、自動的にスクリプトは実行エラーとなります。
経験則ですが、一般的なWebサイトの場合、関数1回の実行で、1,000~2,000件程であれば、6分以内で処理できます。
数千とボリュームの多い一覧を一度に実行したい場合は、コーディングの難易度が上がってしまいますが、下記の記事を参考に取り組んでみましょう。
参考)[GAS]実行時間6分の壁を越えよう(不死鳥関数編)

まとめ

いかがだったでしょうか。スクレイピングを応用していくと、titleとog:titleの差分チェックや、ページ内リンクの404チェックなど、Web運用を行う中で面倒な作業の多くを、機械的に行うことができます。
この機会に、実践してどんどん時間を削減していきましょう。

 

著者紹介

関口 哲平(せきぐち てっぺい)

フロントエンドエンジニア・マークアップエンジニア2年目。Web制作の他、GASやpythonでの作業自動・効率化ツールの制作、APIなどのバックエンド構築(PHP)が守備範囲。コロナ禍は、在宅でカピバラさんのぬいぐるみを傍らにPCと向き合っている。