#05 スプレッドシート+GAS でスクレイピング!
この記事は、2021年のゴールデンウイークに、はてなブログに投稿したものを転載・再構成したものです。
自宅で「Google 認定教育者レベル1」「…レベル2」の Teacher Center に掲載されている問題を見直していました。
そして、その流れで下図のような「スプレッドシート+GAS 」でスクレイピングしてみました!
はじめに
Google の教育者向けの学習サイト「Teacher Center」は、昨年のうちにリニューアルされ、新しい感じの UI に更新されましたが、内容のベースは英語圏だからなのでしょうが、未だに日本語版のコンテンツには誤訳があるような感じがします。少しずつ解消されていますが、仕方のない点だと思います。
以前のサイトがどうだったか記憶していませんが、現在のサイトでは下図のように当該コンテンツがいつ更新されたものなのかがわかるようになっています。
まだまだ誤訳があるからなのか、Google のサービスが更新されているからなのか、理由はわかりませんが、いくつか 2021年 1月に更新されているコンテンツも見かけました。しかしながら、サクサクとページが切り替えられるようなレスポンスのコンテンツではなく、「…レベル1」「…レベル2」のそれぞれで 60 を超えるコンテンツがあり、更新日を手作業で確認するのは現実的ではないと感じました。
そこで、以前から気になっていたスクレイピングにチャレンジしてみることにしました。
準備や調査
わたし自身、これまで「スクレイピング」という言葉は聞いたことがあって興味を持っていたものの、集中して取り組む時間などが確保できず、そのままになっていたものでした。
上記のようなスクレイピングツールと呼ばれるようなものを使うのもいいのでしょうが、自身でプログラミングする方向で考えてみました。いろいろと調べてみると、
Python で HTML を XML 形式で取得して、BeautifulSoup で解読
Google Apps Script(JavaScript)で HTML を XML 形式で取得して、Parser で解読
スプレッドシートの IMPORTXML を使って、正規表現でデータを取得
といった感じでやるみたい。
Google のサービスで Python が使えないわけではないのだけれど、取得したデータをスプレッドシートに出力したかったので、Parser と IMPORTXML を組み合わせて実現することにしました。
スクレイピング(その1:IMPORTXML)
まずは、以下の URL に「…レベル1」の学習コンテンツが一覧になっているので、このページから学習コンテンツの一覧を作成します。
ここで、「Google スプレッドシート」で関数として用意されている IMPORTXML を利用します。
この関数を利用すると、指定された URL からデータを読み込めます。下図のように B2 セルに
=IMPORTXML(B1,"//title")
と指定することで、URL である B1 の Web ページのタイトル(TITLE タグ)の内容を取得できます。
同じように B3 セルに
=IMPORTXML($B$1,"//h3[@class='u-headingitem activitysection__itemname']")
と入力してやると、下図のように B3 から下に、指定された Web ページの該当する見出し(H3 タグ)の内容を一覧にしてくれます。
INPORTXML の 2つ目の引数に指定されている内容は、対象となる Web ページのソースを見て、抜き出したい部分のタグを特定できるように、黄色マーカーの部分の情報を指定してあります。
このように指定することで、B 列にはコンテンツ一覧が作成できました。B3 セルにしか入力していませんが、B3 から下のセルに一覧が作成されます。IMPORTXML については、以下のサイトなどが参考になりました。
https://nf-x.com/blog/efficient/importxml-scraping/
同じように D3 セルに
=IMPORTXML($B$1,"//a[@class='double_click_protection']/@href")
と入力して、B 列のアクセス先となる URL を抽出しています。これも D3 セルにしか入力していませんが、D3 から下のセルに一覧が作成されます。
B3 と D3 の IMPORTXML は、連携しているものではありませんが、公開されている Web ページ側がちゃんと辻褄を合わせた体裁になっているはずなので、問題にはならないと考えています。
B1 に URL を入力すると、B 列・D 列の一覧が自動的に作成されます。
スクレイピング(その2:IMPORTXML 失敗)
前項で D 列に取得したアクセス先の URL は、B1 セルで表示された URL からの相対パスとなっていたので、E 列に B1 セルの内容と加工して結合した絶対パスの URL を作成しました。
E 列の URL を使って、IMPORTXML することで最終目的である更新日を取得することも可能だったのですが、 一度に多くの IMPORTXML でアクセスしてしまうので、正しく情報が取得できませんでした。
今回の用途の場合、最後の更新日の取得については、IMPORTXML で取得するのは適切ではないようです。
スクレイピング(その3:Parser で解読)
前項のように IMPORTXML ではうまく動作しないので、以下のような GAS のスクリプトを作成して、HTML を Parser で解読することにしました。
実際の処理は 20行目からの for によるくり返しの中になります。25行目の UrlFetchApp で Web ページの内容を取得して、30行目の Parser で更新日の部分を抜き出しています。
サーバー側に負担をかけないように、40行目では一度の処理が終わるごとに 3秒のウエイト(待ち時間)を付けてあります。
終わりに
前項で作成した関数を、スプレッドシート上に配置した「日付取得」ボタンを押すことで実行させます。過負荷にならないようにウエイトを入れてあることもあって、実行には時間がかかりますが、簡単な操作で冒頭の画像のようにコンテンツの更新日を確認できるようになりました。
冒頭の画像のように、前回チェックしたときの更新日を保存しておき、それと比較することで更新されたかどうかの判定が行える。 ※冒頭の画像では、H 列に前回の更新日を保存
作成したスプレッドシートや GAS のスクリプトは、シートに依存していないので、シートをコピーして、B1 セルに入力する URL を、以下の「…レベル2」の学習コンテンツに変更すれば、同様に一覧を作成できる。
今回の取り組みで、これまで気になっていたスクレイピングが身近になった気がします。いいネタがあれば、またチャレンジしてみたいと思います。