GAS(Google Apps Script)でWebサイトをスクレイピングする方法の説明です。
matchメソッドで正規表現を駆使してもスクレイピングをできなくはないですが、Parserライブラリを使った方が100倍簡単です。
GASでスクレイピングすれば、毎日何時にとか何時間毎にといったようにWebサイトから定期的に情報収集することができます。
GASライブラリとは
簡単にいってしまえば、他の人が作った関数を利用できる機能がライブラリです。面倒臭い作業も賢い人が作ったライブラリを使えば自分でプログラミングする必要はなくなります。
Parserライブラリを導入する
Parserは、スクレイピングをするときにとても便利なライブラリで、下記で公開されています。
https://script.google.com/home/projects/1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw/edit
ライブラリを使用するときには、スクリプトIDが必要となりますので、
1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw
の部分をコピーしてください。
ライブラリの追加方法
スクリプトエディタを開いてライブラリの「+」をクリックします。
ライブラリ追加画面となりますので、スクリプトIDをペーストして、検索をクリックして追加すればParserライブラリが利用可能となります。
- ParserのスクリプトIDを入力
- 検索をクリック
- 追加をクリック
HTMLデータを取得する
毎日データが変わる 12星座運勢ランキング - Yahoo!占い を使って説明していきます。
先ずは、HTMLデータを取り込みます。
HTMLを取り込むときの注意点は文字コードとして何が使われているかです。文字コードを指定しないと文字化けしてしまいます。
Yahoo!占いで使われている文字コードは "euc-jp” です。<head>から</head>に charsetの記載がありますので探してみてください。
<meta http-equiv="Content-Type" content="text/html; charset=euc-jp">
ちなみに、このブログである「象と散歩」の文字コードは "UTF-8” です。
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/>
GASでHTMLデータを取得するには UrlFetchAppクラスを使いますが、文字コードはgetContentTextで指定します。
function myFunction() {
var url = "https://fortune.yahoo.co.jp/12astro/ranking.html" // Yahoo!占い
var html = UrlFetchApp.fetch(url).getContentText('euc-jp')
Logger.log(html)
}
これでhtmlに格納されたHTMLデータが出力されます。
Parserライブラリの使い方
Parserの書き方は簡単で、抽出したいデータの中にある開始文字列と終了文字列に挟まれている文字列を抽出できます。
Parser.data(‘抽出データ').from(‘開始文字列').to(‘終了文字列').build()
開始と終了に指定する文字列はhtmlタグである必要はありません。
また最後のbuild()関数は、最初に見つけたひとつだけを抽出する場合で、複数のデータを抽出するのであれば、iterate()を使います。
Yahoo!占いのタイトルと更新日を抽出する
では、早速 Yahoo!占い 12星座運勢ランキングからタイトルと更新日を取得してみます。「12星座運勢ランキング」というのは他のところからも取得できますが、画像で指定されているところから抽出してみます。
HTMLソースでは下記の部分となります。
<h2><img src="https://s.yimg.jp/images/fortune/images/common/yftn_tt01_txt08.gif" alt="12星座運勢ランキング"></h2>
<p class="txt">2021年11月6日(土)</p>
「12星座運勢ランキング」を取得するために、直前の文字列 alt=" と直後の文字列 "> を指定します。
更新日には、開始と終了に <p class="txt"> と </p>を指定します。
function myFunction() {
var url = "https://fortune.yahoo.co.jp/12astro/ranking.html" // Yahoo!占い
var html = UrlFetchApp.fetch(url).getContentText('euc-jp')
var title = Parser.data(html).from('alt="').to('">').build()
var lastUpdated = Parser.data(html).from('<p class="txt">').to('</p>').build()
Logger.log('タイトル= ' + title)
Logger.log('更新日 = ' + lastUpdated)
}
実行結果をみるとタイトルが正しく抽出されていません。
タイトル= Yahoo!占い" width="177" height="34
更新日 = 2021年11月6日(土)
前述したように build() は、最初に見つけたものとなるので、
<img src="https://s.yimg.jp/c/logo/f/2.0/fortune_r_34_2x.png" alt="Yahoo!占い" width="177" height="34">
が、先にマッチしてこの部分が抽出されたようです。
もう少し、開始文字列を多くして、他で一致しないようにします。
function myFunction() {
var url = "https://fortune.yahoo.co.jp/12astro/ranking.html" // Yahoo!占い
var html = UrlFetchApp.fetch(url).getContentText('euc-jp')
var title = Parser.data(html).from('txt08.gif" alt="').to('">').build()
var lastUpdated = Parser.data(html).from('<p class="txt">').to('</p>').build()
Logger.log('タイトル= ' + title)
Logger.log('更新日 = ' + lastUpdated)
}
今度は正しく取得できています。
タイトル= 12星座運勢ランキング
更新日 = 2021年11月6日(土)
複数の値を取得する
Yahoo!12星座運勢ランキングのソースをみると、1位から12位まで表形式(tableタグ)で組み立てられています。
1行毎に薄い色と濃い色とで変えているので、簡単に記載するとこんな形です。
<table>
ランキング1位の項目
<tr class="st01">
<td>...</td>
</tr>
ランキング2位の項目
<tr class="st02">
<td>...</td>
</tr>
ランキング3位の項目
<tr class="st01">
<td>...</td>
</tr>
:
</table>
<tr class="st01">で始まっているのが奇数の順位のもので、<tr class="st02">が偶数順位ですが、iterate()を使うと一気に配列として取得できます。
list_odd[5]でランク11位、list_even[5]でランク12位の情報が取得できます。
function myFunction() {
var url = "https://fortune.yahoo.co.jp/12astro/ranking.html" // Yahoo!占い
var html = UrlFetchApp.fetch(url).getContentText('euc-jp')
//奇数順位の星座
var list_odd = Parser.data(html).from('<tr class="st01">').to('</tr>').iterate()
//偶数順位の星座
var list_even = Parser.data(html).from('<tr class="st02">').to('</tr>').iterate()
Logger.log(list_odd[5])
Logger.log(list_even[5])
}
Parserを複数回利用して値を取得する
Parserを繰り返し使用することで目的の値を簡単に取得することができます。
上で取得した各星座のデータからランク、星座名、コメントを取得します。
スクレイピングのプログラミングのコツは、共通点を見つけるということです。共通のロジックでデータが取得できるかという観点でHTMLデータを俯瞰的に見てください。
順位の取得
詳細項目の取得方法について順位を使って説明します。
<td class="st01"> ... </td> の中にランキング情報があり、alt=" ... "> 中に順位がありますので、Paserを2回使って順位を取得します。以下がGASのコードとなります。
function myFunction() {
var url = "https://fortune.yahoo.co.jp/12astro/ranking.html" // Yahoo!占い
var html = UrlFetchApp.fetch(url).getContentText('euc-jp')
//奇数順位の星座
var list_odd = Parser.data(html).from('<tr class="st01">').to('</tr>').iterate()
//ランクを取得
var rank = Parser.data(contents).from('<td class="st01">').to('</td>').build()
rank = Parser.data(rank).from('alt="').to('">').build()
Logger.log(rank)
}
上記で「1位」と表示されます。
順位、星座名、コメントを取得する
下記が、Yahoo! 12星座運勢ランキングから、順位、星座名、コメントを取得するGASのコードとなりますので参考にしてみてください。
function myFunction() {
var url = "https://fortune.yahoo.co.jp/12astro/ranking.html" // Yahoo!占い
var html = UrlFetchApp.fetch(url).getContentText('euc-jp')
//奇数順位の星座
var list_odd = Parser.data(html).from('<tr class="st01">').to('</tr>').iterate()
//偶数順位の星座
var list_even = Parser.data(html).from('<tr class="st02">').to('</tr>').iterate()
for(var i=0; i<list_odd.length; i++) {
//奇数順位の星座
results_odd = parse(list_odd[i])
Logger.log(results_odd)
//偶数順位の星座
results_even = parse(list_even[i])
Logger.log(results_even)
}
}
function parse(contents) {
//ランクを取得
var rank = Parser.data(contents).from('<td class="st01">').to('</td>').build()
rank = Parser.data(rank).from('alt="').to('">').build()
//星座名を取得
var seiza = Parser.data(contents).from('<p class="seiza">').to('</p>').build()
seiza = Parser.data(seiza).from('alt="').to('">').build()
//コメントを取得
var text = Parser.data(contents).from('<p class="ft01">').to('</p>').build()
text = Parser.data(text).from('">').to('</a>').build();
var results =[rank, seiza, text]
return results
}
GASの基礎を学べる参考図書
ある程度プログラミンがわかっていれば、WEBやYoutubeでも十分に調べられると思いますが、初歩的なところからであれば参考図書は有効な学習手段です。
「詳解! Google Apps Script完全入門 [第3版]」は、プラグラミング初心者にわかりやすく説明されています。GASを最初に学ぶ一冊として良書です。