API

PhantomJsCloud GASで動的ページをスクレイピング

PhantomJsCloud

PhantomJsCloudはクラウド上のブラウザを起動し、ページ情報を返してくれるツールです。

無料利用も可能で、無料版の場合は一日に500リクエストまでは無料で利用できます。

有料版にすることでリクエスト制限を以下のように増やしていくことができます。

何で必要なの?

GAS(Google Apps Scripts)でスクレイピング 実装しようとする場合、Parserライブラリを使うことになると思うが、これは動的ページに対応しておらず、静的なページしか取得できない。

例えばYahooニュースの検索結果から以下のような、検索結果数を取得したい場合はParserだけでは取得できない。

yahooニュースのページの挙動として詳細なデータはクライアント側(javascript)で出力されている。サーバからは受け取るページはyahooニュースの枠だけになっている。

Parserではこのサーバから受け取った時点のページ情報しか取得できため、javascriptでクライアント側でページが作成される場合はParserでは取得できない。

(Yahooニュースの検索結果をPhantomJsCloudとGASを用いて取得する方法は最後に記載しています。)

 

そのため、初期ページをjavascriptで生成しているようなページだとjavascriptの処理前のページ情報が取得され、欲しいデータが取得できないことが多々ある。

GASはスプレッドシート 用のjavascript的な立ち位置で本来のjavascriptのようにDOM操作等がサポートされていない

そこで、javascriptで生成されたページを取得しようとした場合にPhantomJsCloudが必要となってくる。

 

問題はある。

このjavascript処理後のページ情報を返してくれるPhantomJsCloudだがどこまでの待機処理を実際に実施しているかは仕様としても謎で、実際に取得できないページも存在する。(大体は取得できる。)

そもそもGASでスクレピングを実装するのはgoogleスプレッドシートへのアウトプットが容易である点と定期実行ができるのみだと思います。

僕自身、アウトプット要件がcsvであればGASは選定しないと思います。。

確かにものすごく楽に実装できるのですが、何だか痒いところに手が届かなかったりと実装が終わる最後までGASで実装できるのかなぁ?という不安要素を残した状態で作業が進むことが多いです。

例えばpythonとかのライブラリでもある、seleniumなどであれば大抵のスクレイピング は実現可否がはじめる段階である程度想定できます。

seleniumなどであればDOM操作や待機処理ができ、柔軟性があるので基本的に何とかなります。

とはいえ、スプレッドシートが広く使われている、このご時世GASで実装する必要性も出てくるので、今回はPhantomJsCloudを用いたスクレイピング について見ていきます。

アカウント登録

https://phantomjscloud.com/にアクセス

✅Loginボタンを押下

✅Sign Upをクリック

✅アカウントを登録

✅登録後、APIKeyが発行される

GASでの利用方法

//独自関数
function phantomJSCloud(URL) {

  let key = "<PhantomJsCloudのAPIキー>";

  //HTTPSレスポンスのオプション項目を設定する
  let option =
    {
      url:URL,
      renderType:"HTML",
      outputAsJson:true
    };

  //オプション項目をJSONにしてエンコードする
  let payload = JSON.stringify(option);
  payload = encodeURIComponent(payload);

  //PhantomJsCloudのAPIリクエストを行うためのURLを設定
  let apiUrl = "https://phantomjscloud.com/api/browser/v2/"+ key +"/?request=" + payload;
  let response = UrlFetchApp.fetch(apiUrl);
  let json = JSON.parse(response.getContentText());
  let source = json["content"]["data"];
  return source;
}

 

上記、関数として定義し呼び出すことでページデータを取得することができます。
この戻り値に対してはParserライブラリと同様に以下のように取得したい値を取得することができるようになります。

Parser.data("<戻りのページ情報>")
      .from("xxxx") 
      .to("xxx") 
      .iterate(); 

 

Yahooニュースページのスクレイピング

実際に動的に生成されるYahooニュースのページをスクレイピングして検索結果数を取得する方法を記載します。

✅Parserの追加

ライブラリの追加から、スクリプトID入力欄に「1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw」を検索して追加

今回Parserはページ情報の取得(リクエスト)では使用しませんが、PhantomJsCloudで取得したページ情報を解析する部分でParserを利用しています。

✅コード.gsに以下コードを全てコピーして貼り付ける

function myFunction() {

  let spreadSheet = SpreadsheetApp.getActive()
  let sheet = spreadSheet.getSheets()[0]
  let html = phantomJSCloudScraping("https://news.yahoo.co.jp/search?p=オリンピック");
  let total = 
      Parser.data(html)
      .from('<div class="sc-kNEibC ctQJXs"><span>')
      .to('</span><span>件</span></div>')
      .iterate();

  sheet.getRange(1,1).setValue(total)

  
}


function phantomJSCloudScraping(URL) {
  let key = "<ここにはphantomJSCloudのライセンスキーを入力>";

  //HTTPSレスポンスに設定するペイロードのオプション項目を設定する
  let option =
    {url:URL,
    renderType:"HTML",
    outputAsJson:true,
    };

  //オプション項目をJSONにしてペイロードとして定義し、エンコードする
  let payload = JSON.stringify(option);
  payload = encodeURIComponent(payload);

  //PhantomJsCloudのAPIリクエストを行うためのURLを設定
  let apiUrl = "https://phantomjscloud.com/api/browser/v2/"+ key +"/?request=" + payload;
  //設定したAPIリクエスト用URLにフェッチして、情報を取得する。
  let response = UrlFetchApp.fetch(apiUrl);
  //取得したjsonデータを配列データとして格納
  let json = JSON.parse(response.getContentText());
  //APIから取得したデータからJSから生成されたソースコードを取得
  let source = json["content"]["data"];
  return source;
}

“<ここにはphantomJSCloudのライセンスキーを入力>”;の箇所にはご自身で取得したライセンスキーに置き換えてください。

✅実行する

実行後スプレッドシートのA1セルにyahooニュースで「オリンピック」で検索したい際の検索結果数が出力されます。