はじめに
Google Apps Script(GAS)は、スプレッドシートと連携した自動化処理に非常に便利です。中でも「Webページの情報を自動で取得し、スプレッドシートに転記したい」というニーズは非常に多いです。
一方でGAS単体ではクライアント側でレンダリングされる動的なサイトのHTML要素を取得することができません。
そこでこの記事では、クライアント側でレンダリングされる動的なWebサイトのスクレイピング方法を解説します。
この記事で触れないこと
- GASの操作
- Cheerioの使い方
- スクレイピングの実装方法
GASでのスクレイピングにCheerioを使う
GAS単体ではDOMの解析ができませんが、Cheerioというライブラリを使うことで、Node.js風にjQueryライクなDOM操作が可能になります。
GASとCheerioを組み合わせると、取得したデータをスプレッドシートに転記する処理も簡単に書けます。業務の自動化や定期的なデータ収集に最適です。
しかし、Cheerioには限界がある
便利なCheerioですが、 JavaScriptで描画されるコンテンツ(いわゆる動的サイト) には対応できません。これは次のような理由によるものです:
- UrlFetchAppで取得できるHTMLは、 JavaScriptの実行前の状態
- つまり、 画面上に表示されている内容と取得できるHTMLが異なる
- Cheerioはあくまで「静的なHTML」に対する処理を行うライブラリ
具体的な例
たとえば、SPA(Single Page Application)で作られたECサイトの商品リストや、チャートライブラリで動的に描画されるグラフ情報などは、Cheerioでは取得できません。
解決方法
このような「JavaScriptで描画されたあとのHTML」を取得するには、ヘッドレスブラウザを使った描画処理が必要になります。そこで登場するのがPhantomJSCloudです。
PhantomJSCloudとは?
PhantomJSCloudは、クラウド上でヘッドレスブラウザを実行し、描画済みのHTMLを取得できるAPIサービスです。
PhantomJSCloudを使い以下の流れでスクレイピングが実行可能になります。
- PhantomJSを呼び出しHTMLを描画
- 描画されたHTMLをGASに返す
- Cheerioでスクレイピング実行
実装編
PhantomJSCloudのAPIキーを取得する
PhantomJSCloudのページにアクセスし、APIキーを取得します。
Sign up now
のボタンから登録します。
登録が完了するとAPIキーが表示され、以降PhantomJSCloudのエンドポイントへリクエストを送るために必要なためコピーして控えておきます。
エンドポイントへのリクエストの書き方
GET
http(s)://PhantomJsCloud.com/api/browser/v2/[先ほど発行したAPIキー]
/?request=リクエストのJSONオブジェクト
POST
http(s)://PhantomJsCloud.com/api/browser/v2/[先ほど発行したAPIキー]
/
リクエストのJSONオブジェクトの書き方
プロパティはたくさんありますが、とりあえず最低限必要なもののみ紹介します。
- url(必須)
- 操作したい対象のページURL
- render
- レスポンスのレンダリングタイプ。HTMLとすればHTMLが戻される
- outPutAsJson
* - overseerScript
- 対象のページでクリックやフォーム入力などブラウザ操作するスクリプトを渡す
- 詳細はこちらを参考
- Puppeteerのスクリプトの80%をサポートしている
参考
GETリクエストを送ってページを取得してみる
サクッとQiitaのトップページのHTMLを取得してみます。
HTMLが返されるので結果をCheerioに渡してあげればスクレイピングが可能です。
function myFunction() {
const apikey = "apiキー";
const options = {
url: "https://qiita.com/",
renderType: "HTML",
outputAsJson: true,
}
// encodeURIComponentでエンコードする必要があるためエンコード
const requestJson = encodeURIComponent(JSON.stringify(options));
const endpoint = `https://phantomJsCloud.com/api/browser/v2/${apikey}/?request=${requestJson}`
const response = UrlFetchApp.fetch(endpoint).getContentText();
const html = JSON.parse(response)['content']['data'];
console.log(html);
}
ログイン処理が必要な場合
ログインが必要な場合にはPOSTリクエストを送り、overseeerScript
にログインフォームを操作するスクリプトを渡すことで実装が可能になります。
今回はPhantomJSCloudにあるサンプルのログインページにユーザー名・パスワードを入力してログインしてみます。
function myFunction() {
const apikey = "apiキー";
const endpoint = `https://phantomJsCloud.com/api/browser/v2/${apikey}/`
const payload = {
url: "https://phantomjscloud.com/examples/corpus/automation.html",
renderType: "HTML",
outputAsJson: true,
overseerScript: 'await page.waitForSelector("input[name=id]"); \
await page.type("input[name=id]", user, {delay:100}); \
await page.type("input[name=pass]", pass, {delay:100}); \
page.click("input[type=button][value=Login]"); \
await waitForNavigation();',
}
const options = {
method: "POST",
payload: JSON.stringify(payload)
}
const response = UrlFetchApp.fetch(endpoint, options);
const html = JSON.parse(response)["content"]["data"];
console.log(html)
}
overseerScript
内で使っているメソッドのドキュメントはこちらになります。
このスクリプトを実行するとログイン後の画面のHTMLが返されるのでスクレイピングが可能になります。
またこれ以外にログイン後の画面でボタン操作がしたいなどあればoverseerScript
内に追加のコードを書くことで実現可能です。
最後に
GASでのスクレイピング方法の情報は多くありますが、動的サイトにログイン処理をしてスクレイピングする情報が少なかったので苦労しました。
この情報がどなたかの参考になれば幸いです。