【コード公開】Google Apps Script(gas)でwebスクレイピング

【コード公開】Google Apps Script(gas)でwebスクレイピング

「webスクレイピングをやってみたい」
「google Apps Script(GAS)でアプリをつくってみたい」

そんな方に向けて、記事を書いています。

はじめまして。現役エンジニアのkazと申します。
実際に私が作成したアプリをもとに解説記事を作成しました。
あなたのプログラミングの

webスクレイピングとは

wikipediaでwebスクレイピングを検索すると以下のような説明が出てきます。

ウェブスクレイピングとは、ウェブサイトから情報を抽出するコンピュータソフトウェア技術のこと。ウェブ・クローラーあるいはウェブ・スパイダーとも呼ばれる。 通常このようなソフトウェアプログラムは低レベルのHTTPを実装することで、もしくはウェブブラウザを埋め込むことによって、WWWのコンテンツを取得する。

wikipedia:ウェブスクレイピング

簡単に言うと、サイトの情報を取得することをスクレイピングといいます。
スクレイピングは、Googleがサイトの情報を取得して、検索結果を表示するときなんかにも使われています。

webスクレイピングのやり方について

今回のスクレイピングは、TSUTAYAのサイトから新作リリース情報として、
先週リリース、今週リリース、来週リリースをそれぞれのURLから情報を取得します。

取得した情報をgoogleのスプレッドシートに出力します。
下記のコードを定期実行することで、スプレイピングの完成です。

scraping(main)関数

まずは、main関数を書いていきます。
①idには、googleのスプレッドシートのidを入力します。
②出力対象のスプレッドシートをクリアします。
③getRelease関数を呼び出します。

function scraping() {
  try{
    var id,spreadSheet,sheetName;
  
    id = "xxxx";  
    spreadSheet = SpreadsheetApp.openById(id);  
  
    //スプレッドシートクリア
    spreadSheet.getSheetByName("先週").clearContents();
    spreadSheet.getSheetByName("今週").clearContents();
    spreadSheet.getSheetByName("来週").clearContents();
    
    //新作情報出力
    getRelease('https://tsutaya.tsite.jp/release/movie/1/1?sc_int=tsutaya_release_week',"先週");
    getRelease('https://tsutaya.tsite.jp/release/movie/1/2?sc_int=tsutaya_release_week',"今週");
    getRelease('https://tsutaya.tsite.jp/release/movie/1/3?sc_int=tsutaya_release_week',"来週");
  }catch(e){
      outputLog(e);
  }
}

getRelease関数

getRelease関数では、GASライブラリのParserを使用して、サイトから情報を取得します。
※Parser : 構文解析を行うためのプログラムの総称
①UrlFetchApp.fetchで引数getUrlで指定されたURLのすべてのサイト情報(HTML)を取得
②取得したすべてのサイト情報から必要な部分だけ抜き出す
③スプレッドシートへ出力

function getRelease(getUrl,week){
  var j=0;
  var url;
  // 指定URLからすべてのHTMLを取得
  var content = UrlFetchApp.fetch(getUrl).getContentText('UTF-8');
  
  // <ul>内のリストをすべて抜き出す
  var content_ul = Parser.data(content).from('<ul class="c_thumb_list_row c_js_equal_height" data-eh-el=c_thumb_info data-eh-row=5 data-eh-row-sp=2>').to('</ul>').build();
  // <ul>内のタイトルをすべて抜き出す
  var content_title = Parser.data(content_ul).from('<p class=c_thumb_tit>').to('</p>').iterate();
  // <ul>内のリリース日をすべて抜き出す
  var content_date = Parser.data(content_ul).from('<p class=c_thumb_date>').to('</p>').iterate();
  // <ul>内の画像URLをすべて抜き出す
  var content_imgurl = Parser.data(content_ul).from('<img src="').to('">').iterate();
  // <ul>内の画像URLをすべて抜き出す
  var content_url = Parser.data(content_ul).from('<a href="').to('">').iterate();  
  
  // スプレッドシートへ出力
  for(i=0; i<content_title.length ;i++){
    url = "https://tsutaya.tsite.jp/" + content_url[j];
    outputReleaseInfo(content_title[i].substring(content_title[i].indexOf('>')+1,content_title[i].lastIndexOf('<')),
           content_date[i],content_imgurl[i],url,week);
    // urlのみ2つずつ取得されるため、2つずつ進める
    j = j+2;
  }
}

outputReleaseInfo関数

outputReleaseInfo関数では、取得したサイト情報をスプレッドシートに出力します。

function outputReleaseInfo(title,date,imgurl,url,week) {
  var id,spreadSheet;
  
  id = "xxxxx";  
  spreadSheet = SpreadsheetApp.openById(id);  
  
  //スプレッドシート出力
  spreadSheet.getSheetByName(week).appendRow([title, date, imgurl,url]);
}

コード全体

function scraping() {
  try{
    var id,spreadSheet,sheetName;
  
    id = "xxxx";  
    spreadSheet = SpreadsheetApp.openById(id);  
  
    //スプレッドシートクリア
    spreadSheet.getSheetByName("先週").clearContents();
    spreadSheet.getSheetByName("今週").clearContents();
    spreadSheet.getSheetByName("来週").clearContents();
    
    //新作情報出力
    getRelease('https://tsutaya.tsite.jp/release/movie/1/1?sc_int=tsutaya_release_week',"先週");
    getRelease('https://tsutaya.tsite.jp/release/movie/1/2?sc_int=tsutaya_release_week',"今週");
    getRelease('https://tsutaya.tsite.jp/release/movie/1/3?sc_int=tsutaya_release_week',"来週");
  }catch(e){
      outputLog(e);
  }
}

function getRelease(getUrl,week){
  var j=0;
  var url;
  // 指定URLからすべてのHTMLを取得
  var content = UrlFetchApp.fetch(getUrl).getContentText('UTF-8');
  
  // <ul>内のリストをすべて抜き出す
  var content_ul = Parser.data(content).from('<ul class="c_thumb_list_row c_js_equal_height" data-eh-el=c_thumb_info data-eh-row=5 data-eh-row-sp=2>').to('</ul>').build();
  // <ul>内のタイトルをすべて抜き出す
  var content_title = Parser.data(content_ul).from('<p class=c_thumb_tit>').to('</p>').iterate();
  // <ul>内のリリース日をすべて抜き出す
  var content_date = Parser.data(content_ul).from('<p class=c_thumb_date>').to('</p>').iterate();
  // <ul>内の画像URLをすべて抜き出す
  var content_imgurl = Parser.data(content_ul).from('<img src="').to('">').iterate();
  // <ul>内の画像URLをすべて抜き出す
  var content_url = Parser.data(content_ul).from('<a href="').to('">').iterate();  
  
  // スプレッドシートへ出力
  for(i=0; i<content_title.length ;i++){
    url = "https://tsutaya.tsite.jp/" + content_url[j];
    outputReleaseInfo(content_title[i].substring(content_title[i].indexOf('>')+1,content_title[i].lastIndexOf('<')),
           content_date[i],content_imgurl[i],url,week);
    // urlのみ2つずつ取得されるため、2つずつ進める
    j = j+2;
  }
}

//新作情報をスプレッドシートに書き出す
function outputReleaseInfo(title,date,imgurl,url,week) {
  var id,spreadSheet;
  
  id = "xxxxx";  
  spreadSheet = SpreadsheetApp.openById(id);  
  
  //スプレッドシート出力
  spreadSheet.getSheetByName(week).appendRow([title, date, imgurl,url]);
}

//logファイルにログを書き出す
function outputLog(txt) {
  var id,spreadSheet,sheetName;
  
  id = "xxxxx";  
  spreadSheet = SpreadsheetApp.openById(id);  
  sheetName = "Linebot_log";
  
  spreadSheet.getSheetByName(sheetName).appendRow(
    [new Date(), txt]
  );
}

難しいところ

スプレッドシートの出力やサイト情報の取得は、おまじないだと思ってもらえれば大丈夫です。
サイト情報を取得した後、必要な情報を抜き出すところが難しいかもしれません。
必要な部分を指定する際に正規表現を使用しますので、初心者の方が躓くポイントかもしれません。

抜き出すところに関しては、取得するサイトによってHTMLの内容が違うので、サイトが変われば、変えなければいけません。

結果

スクレイピングを行った結果、画像のようにスプレッドシートに出力されます。

A列:新作タイトル
B列:新作リリース日
C列:サムネイル
D列:新作タイトルのURL