Google Apps Scriptでスクレイピングを極める

Google Apps Scriptで意外とよく利用されてるのが、ウェブページのスクレイピング。今どきのウェブサービスだとREST APIが装備されてるのが半ば当たり前になってきていますが、そうではないサイトや提供されていないサイトも非常に多いです。

そういったサイトのデータを手動で検索し値をコピー、貼り付けて整形してから処理をするのではスマートではありません。そういったケースを自動化するのがスクレイピングの主な目的です。但し、連続してスクレイピングを行うと相手方ウェブサイトに多大な負荷を掛け、また場合によってはアクセスを禁じられる恐れもあるため、利用する頻度やルールは守りましょう。

難易度:

今回使用するサービス等

以前、PuppeteerとCheerioを使ってテーブルデータをスクレイピングしましたが、参考になるかと思います。

Puppeteerでテーブルデータを取得する

事前準備

注意事項

Google Apps Scriptでのスクレイピングですが、Node.js + Puppeteerで作る場合と異なり、GASだけでスクレイピングする場合には色々と注意事項があります。主に

  • 6分の実行時間制限がある
  • Google Workspaceの場合、UrlfetchAppは100,000 回/1日の制限事項がある
  • JavaScript多用の動的サイトのスクレイピングは出来ない(Puppeteerは可能)
  • 大規模なデータの取得や画面遷移を伴うデータの取得に向いていない
  • フォームなどのパラメータ入力の結果をスクレイピングするのには向いていない

これらに該当しそうなケースについては、Google Apps Scriptではなく、Puppeteerなどでスクレイピング環境を構築するほうが良いでしょう。

ライブラリの追加

以前は、HTML Parserライブラリ(1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw)を使うのが主流でしたが、正直言って使いにくい。ので、最近はNode.jsなどでもおなじみのjQuery的にHTMLを処理できるCheerio.gsを使うのが非常に楽に処理できるので、おすすめです。

以下の手順で追加します。

  1. スクリプトエディタを開く
  2. 左サイドバーの「ライブラリ」の+ボタンをクリックする
  3. スクリプトIDに「1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0」を追加する
  4. 検索をクリック
  5. 最新バージョンが出てくるので、追加ボタンをクリック。Cheerioで呼び出すことになります。

図:jQueryの使い手ならすぐ使いこなせるよ

シンプルなスクレイピング

対象ページのHTMLの構造

Google Apps Scriptでの最もシンプルなスクレイピングです。UrlfetchAppを利用してページの取得になります。シンプルではありますが、Puppeteerを使うわけではないので、注意事項にもあるように、最近の主流である動的なサイトのスクレイピングは出来ません。Ajaxの処理結果でサイトを表示してる場合、処理前の何もないページを拾う事になってしまいます。

今回は医薬品コードサーチにて、ロキソニンを調べデータを取り出してみようと思います。検索をすると医薬品名にマッチした候補が列挙、そのURL先に詳細なGS1/JANコードや、包装形態などの情報が含まれています。

対象ページの構造をChrome Developer Toolで調べてみると、医薬品情報はTableで構築されていて、Class名がtable001となっています。また、各セルのclass名はfs13 talというものが指定されてるのがわかります。

図:HTMLの構造を事前に調べておく

ソースコード

  • urlfetchappのgetContentTextにてHTMLをスクレイピングしています
  • スクレイピングした内容をCheerio.loadに渡し、jQuery的な取り出しを可能にします。
  • 今回は指定クラスのtdの中身を取り出すので、$(‘.table001 td’)を指定し、ループで回しています。
  • $(element).text()にてtd内のテキストだけを取り出しています。
  • 今回のテーブルは3列の仕様なので、3つ値を一時配列に入れてから、書込み用のdrugmanの配列にpushしています
  • 1行文取れたら、一時配列を初期化し次の3列を取りに行きます。
  • データの書き出しは一発で行います。

実行結果

今回は検索結果が6件程度なので、この程度のスクリプトで取得できましたが、検索結果が多いケースなどは更に工夫が必要になります。また、更にリンク先も取得したい場合には、データのとり方を変えて、リンク先もスクレイピングが必要になるかと思います。

図:検索結果の部分だけを取得できた

Puppeteerを利用する

Google Apps Scriptでは動的なサイトの操作であったり、スクレイピングが出来ませんが、Google Cloud Functionsを利用し、Puppeteerを動かす事で、動的なサイトや複雑なサイトの処理を行わせる事が出来ます。この場合、Google Apps Script側はCloud Functionsの発火とデータの受取に徹し、実際のスクレイピング処理はCloud Functionsが担当するといった役割分担を行います。

Google Apps ScriptでCloud Functionsの関数を実行する

Cloud Functionの準備

まず、Cloud FunctionsでPuppeteerを利用できるようにします。事前に請求先アカウント、サービスアカウントが必要ですが、最初の200万回までは無償(月間)で利用が可能のようです。以下の手順で準備します。

  1. Cloud Consoleにログインする
  2. 右上のハンバーガーメニュー(≡)をクリックし、サーバーレス項目にあるCloud Functionsをクリック
  3. 関数を作成をクリック
  4. 関数名を入れて、us-central1のリージョン、トリガーはHTTP、今回は未認証を選びます。
  5. この時、URLが生成されてるのでコピーしておく
  6. 保存をクリックする
  7. 続けて下にある「ランタイム、ビルド、接続の設定」をクリック
  8. メモリは512MBを指定、使用するサービスアカウントの指定をして次へをクリック
  9. Cloud Build APIをオンにしろといわれるので、APIを有効化する
  10. ランタイムでは、今回はNode.js 12を指定、エントリポイントは最初に実行する関数名を指定します。今回はgetScrapingとしました。
  11. package.jsonをクリックして、puppeteerをdependenciesに追記する

これでとりあえず、準備は完了。とりあえずデプロイボタンを押します。但しこのデプロイは緑色のチェックマークがついたら成功なのですが、かなり時間が掛かります。

※実行できるユーザを追加したい場合は、権限タブにそのユーザのメアドを追加する必要性があります。再度コードを編集する場合は、編集ボタンをクリックします。

図:以前とだいぶUIが変わっている

図:サービスアカウントとRAMの指定

ソースコード

ソースコードを再編集して、デプロイを押せば実行可能な状態になります。緑色のチェックマークが付けばデプロイ成功。今回はリクエスト側からURLを引数で取って、そのページを取得して返す仕組みにしています。

デプロイと実行時のchromiumダウンロードに時間が掛かるので、他の環境で開発して動くことを確認したコードをアップすると良いです。テストではコード内にURLを記述して、準備の5.で取得したURLを叩くと実行テストと結果が手に入ります(但し認証を入れてると403エラーが出てしまうので一時解除しておきましょう)

図:デプロイ成功したらOK

GAS側コード

  • puppeteerのモジュール読み込みで結構時間が掛かります。故に大量のスクレイピングには向いていません。
  • また、複数同時にリクエストを受けることを考えて、GCF側のインスタンス数をそれだけ増やしておくと良いでしょう(今回は1なので、1度に1回しか受け付けられません)
  • gcfurlに準備でコピーしておいたGCF側のURLを記述します。
  • スクレイピングするURLをpayloadとして記述し、POSTで送信します。
  • レスポンスコードは今回200しか用意していませんが、色々用意して返してあげるようにすると便利です。
  • レスポンスデータは配列なので、JSON.parseしてから取得すると取り出せます。
  • 今回のページはなぜか、配列の1つ目が空っぽなので、shiftで削除させています。
  • 最後は配列データをシートに一発で書き込みをさせています。

GCF側コード

  • 今回は未認証のままなので、URLを知られてしまうと無限に叩かれてしまうので注意
  • テーブルデータを二次元配列に変換して、ステータスコードとともに返却しています。
  • Node.jsで記述してるので、GCF側でcheerioを使ってスクレイピングしたデータの処理をやらせる事も可能です。

図:テストで無事スクレイピングできた

実行制限をつけたい場合

今回は実行制限を付けずに、Cloud FunctionsのPuppeteerを動作させています。しかし、実際には実行制限を加えないと、URLを知っていれば誰でも叩ける状態になりかねません。そこで、実際に実行するには、特定のメンバーだけに制限したいというケースは、以下のエントリーを参考に、実行できるメンバーを制限しましょう。

Google Workspaceの場合、デフォルトでは組織外の人間はメンバーに追加しても動作しませんので、組織内だけで済みますが、オープンになってる場合には要注意です。

Google Apps ScriptでCloud Functionsに実行制限付でアクセス 最新版

PhantomJS Cloudを利用する

お手軽にJavaScriptを使った動的サイトにも対応してるPhantomJS Cloudを利用してのスクレイピングをGoogle Apps Scriptから操作する事が可能です。クリックやページ遷移などはちょっと工夫が必要みたいです。

事前準備

PhantomJS Cloudは現在、500ページ/1日はフリーで利用することが可能です。元々は、すでに開発終了したPhantomJSを元にクラウドで利用できるようにしたサービスです。利用するには、サインアップしAPIキーを取得する必要があります。以下の手順で取得します。

  1. 公式サイトに移動してsing up nowをクリックする
  2. create an accountのページでメアドを入れて、ロボットチェックをしたらsing upをクリック
  3. メールが届くので、リンクをクリックして開く
  4. パスワードを設定してFinish and Loginをクリック
  5. すると、API Keyが表示されるので、コピーしておく

これで完了です。

図:API Keyを取得します

ソースコード

  • 後半はこれまで同様、Cheerio.gsに食わせて、解析をすればOKです。
  • レスポンスデータの中のcontent -> dataの中にスクレイピングしたHTMLデータが入ってるので注意。
  • Cloud Functionsのような環境構築が不要な点は楽です。
  • Clickなどの複雑な操作はAPIドキュメントを読むとoverseerScript指定にて、Puppeteerのように出来るようです。

図:スクレイピングデータの格納場所に注意

関連リンク

共有してみる:

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。