Google Apps Scriptでウェブスクレイピング

シェアする

  • このエントリーをはてなブックマークに追加

最近ウェブスクレイピングをする機会があったのでその際に使用したGAS(Google Apps Script)での処理をまとめてみました。

大まかな処理の流れ

ウェブスクレイピングでの処理の流れは以下のようになっています。

① HTTPリクエストを送信してレスポンスを取得
(ブラウザでアクセスするような感じ)

② レスポンスからページのソースを取得
(ウェブページで、”右クリック”>”ページのソースを取得”した時の内容)

③ ソースから特定の部分を抽出し必要があれば整形

④ 出来上がった情報をスプレッドシートに書き込んだりSlackやLINEに通知したり…

(1) HTTPリクエスト

1.1 シンプルなGETリクエスト

ログインなどを行わず単にアクセスするだけなら以下のように簡単な処理でページのソースを取得することができます。

//メソッドにGETを指定
var options = {
  method : "GET"
};

//アクセス先URLにGETリクエストを送信し、レスポンスを取得
var response = UrlFetchApp.fetch("アクセス先URL",options);

//レスポンスからページソース(内容)を取得
var content = response.getContentText("UTF-8");

1.2 簡単なログイン処理

//ログイン情報をセット
var payload = {
  id : "id",
  pass : "pass"
};

//メソッドにPOSTを指定しログイン情報を設定
var options = {
  method : "POST",
  payload : payload
};

//アクセス先URLにPOSTリクエストを送信し、レスポンスを取得
var response = UrlFetchApp.fetch("ログイン時のPOST先URL", options);

//レスポンスからクッキー(ログイン中の情報)を取得
var cookies = response.getHeaders()["Set-Cookie"];

//クッキーをヘッダにセット
var headers = {
  Cookie : cookies
};

//メソッドにGETを指定しヘッダを設定
options = {
  method : "GET",
  headers : headers
};

//アクセス先URLにGETリクエストを送信し、レスポンスを取得
response = UrlFetchApp.fetch("アクセス先URL",options);

//レスポンスからページソース(内容)を取得
var content = response.getContentText("UTF-8");

スクレイピング対象のページによってログイン処理は様々なため、ブラウザの開発者ツールなどで通信の流れやクッキーの状態を確認しながら編集することをおすすめします。

以下はUrlFetchAppクラスを用いたこれらの処理に関する公式の資料です。

(2) ページ内情報の抽出

次に先ほど取得したページの内容から特定の情報を抽出します。

本来であればHTMLの要素を指定するだけで簡単に情報を抽出することができるParserライブラリなどを使用しますが、今回は正規表現を使って抽出してみます。面倒に感じるかもしれませんが一度に複数の情報を抽出したりなど柔軟性は高いと思うので是非やってみてください。

//レスポンスからページソース(内容)を取得
var content = response.getContentText("UTF-8");

/* コンテンツ例

<html>
  <head>
    <meta charset="utf-8">
    <title>タイトル</title>
  </head>
  <body>
    <div>1.あいうえお</div>
    <div>2.かきくけこ</div>
    <div>3.さしすせそ</div>
  </body>
</html>

*/

//正規表現を用意
var regex = /<div>(.*)<\/div>/g;

var match;
var ct = 0;
var data = [];

while((match = regex.exec(content)) !== null){
  Logger.log(match);
  data[ct] = match[1];
  ct++;
}
/*
Logger.log(match);
[マッチした全体,カッコ内の文字列1,2,3,,,]
while(1)
  match[0] <div>1.あいうえお</div>
  match[1] 1.あいうえお
while(2)
  match[0] <div>2.かきくけこ</div>
  match[1] 2.かきくけこ
while(3)
  match[0] <div>3.さしすせそ</div>
  match[1] 3.さしすせそ
*/

/*
複数をまとめて処理する場合(離れた部分の抽出など)
var regexArr = [/正規表現1/g,/正規表現2/g,/正規表現3/g,/正規表現4/g];

for文を使い配列に格納した4つの正規表現を実行
for(var i=0; i<regexArr.length; i++){
  while((match = regexArr[i].exec(content)) !== null){
    data[ct] = match[1];
    ct++;
  }
}
*/

正規表現:/<div>(.*)<\/div>/g を実行した場合の結果は以下のようになります。Full matchの部分がマッチしている全体、Group 1.の部分が正規表現内のカッコで括った抽出する中身です。それらが計3回分あり、while文によって続けて処理を行っています。

正規表現のテストは以下のサイトがおすすめです。

Online regex tester, debugger with highlighting for PHP, PCRE, Python, Golang and JavaScript.

(3) 抽出した情報の整形

ソースから情報を抽出できた!!けどHTMLタグなど不要な部分が残ってしまう場合にそれらを取り除いたり別の文字に変換する処理を行います。

3.1 HTMLタグの除去

var content = response.getContentText("UTF-8");

//string.replace(/正規表現/ig,"変換文字列");
//フラグのiは文字の大小を無視、gはマッチした全てをリターン
var plain = content.replace(/<\/?[^>]+>/ig, "");

3.2 HTML特殊文字の変換

content.replace(/&lt;/ig,"<");
content.replace(/&gt;/ig,">");
content.replace(/&amp;/ig,"&");
content.replace(/&quot;/ig,"\"");
content.replace(/&apos;/ig,"'");

このように文字の変換も行うことができるので環境に合わせて作ってみてください。

(4) データの保存や通知

4.1 スプレッドシートへの保存

//シートの取得
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("シート名");

//内容の書き込み
  //特定セル
  sheet.getRange("A1").setValue(data);
  //特定範囲(二次元配列)
  sheet.getRange("A1:B2").setValues(dataArr);
  //全て(二次元配列)
  sheet.getDataRange().setValues(dataArr);

//内容の読み込み
  //特定セル
  var read = sheet.getRange("A1").getValue();
  //特定範囲(二次元配列)
  var readArr = sheet.getRange("A1:B2").getValues();
  //全て(二次元配列)
  var readArr = sheet.getDataRange().getValues();

シートの読み書きを頻繁に行うと処理が遅くなってしまうので、たくさん処理を行う場合はgetValues()メソッドとsetValues()メソッドを使うことをおすすめします。

getDataRange().getValues()ではシートの内容全てを二次元配列として返し、getDataRange().setValues(二次元配列)ではgetValues()したときと同じ大きさの二次元配列を1回で書き込むことができます。

4.2 Slackへの通知

今回はIncoming Webhookを使用しました。

Incoming Webhooks are a simple way to post messages from external sources into Slack. They make use of normal HTTP requests with a JSON payload, which includes ...

Slackのワークスペースにインストールして設定を行います。
アプリの設定後、GAS側で以下のコードを使用してください。

var slackURL = "Webhook URL";

var message = "送信するテキストデータ";
//送信データ(オブジェクト型)の作成
var obj = {
  username : "Slack上のユーザ名",
  text : message
};

//オブジェクト型をJSON型に変換しペイロードを作成
var payload = JSON.stringify(obj);

//メソッドにPOSTを指定
var options = {
  method : "POST",
  contentType : "application/json",
  payload : payload
};

//通知
UrlFetchApp.fetch(slackURL,options);

これでアプリ側に設定したチャンネルに通知を送ることができます。

(参考) Slackへのファイルアップロード

Slackへファイルも送信したい!という場合はSlack APIのアプリを新規作成します。

Create New Appで新規作成後、メニューのOAuth & Permissionsから以下のスコープを設定します。

このスコープを設定することでファイルのアップロードが可能になります。

次にこのアプリのトークンを取得してコード内のtoken変数に代入します。先ほどのスコープ設定から上にいくと画像と同じ部分があると思います。この2つあるトークンの内、赤枠で囲ったOAuth Access Tokenをコピーします。

GAS側で以下のコードを設定し完了です。

//データの用意
var fileName = "ファイル名";
var fileData = UrlFetchApp.fetch("ダウンロード先URL",options).getBlob();

var slackUpURL = "https://slack.com/api/files.upload";
var token = "OAuth Access Token";

//各データ設定(チャンネルIDはWEB版SlackのURLに書いてあります)
var payload = {
  token : token,
  channels : "チャンネルID",
  title : fileName,
  filename : fileName,
  file : fileData
};

//メソッドにPOSTを指定
var options = {
  method : "POST",
  payload : payload
};

//アップロード
UrlFetchApp.fetch(slackUpURL,options);

4.3 LINEへの通知

LINEへの通知はLINE Notifyを使用します。

LINE NotifyはGitHub,IFTTT,MackerelなどのWebサービスからの通知を、LINEで受信することが出来る便利なサービスです。

設定後、以下のコードを使用します。

var lineURL = "https://notify-api.line.me/api/notify";
var token = ["LINE Notifyトークン"];

//"&"などをそのまま送信するとテキストがそこで途切れるためURIエンコードを行う
var message = encodeURIComponent(data);

//メソッドにPOSTを指定しヘッダなどを設定
var options = {
  method  : "POST",
  headers : {"Authorization" : "Bearer "+ token},
  payload : "message=" + message
};

//通知
UrlFetchApp.fetch(lineURL,options);

その他細かい処理

内容判定

//レスポンスからページソース(内容)を取得
var content = response.getContentText("UTF-8");

//正規表現にマッチするものがあれば処理を実行
if(content.match(/正規表現/g)){
  処理;
}

他にあれば随時追加しようと思います。

以上がGASを用いたウェブスクレイピングのまとめです。
不備不明点があればコメントをお願いします。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

コメントをどうぞ!

avatar
  Subscribe  
更新通知を受け取る »