Edited at

Google Apps Script でスクレイピングがうまく出来ない場合にチェックするポイント

必要に駆られて行った調査をまとめました。

間違いや良い代替策等ありましたらコメント下さい。


要約


  • 世のウェブサイトは Valid でないことが多いので IMPORTXML() では値が取れないことが多い。

  • 同じく XmlService.parse() も Valid であることが前提なのでパースエラーが起こりやすい。


    • 正規表現で値を取得する。



  • JavaScript で動的にコンテンツを生成しているサイトでは UrlFetchApp でコンテンツを取得できない。


    • PhantomJS Cloud のようなサービスと組み合わせる必要がある。




事例


IMPORTXML() で値が取れない。#N/A と表示される。

IMPORTXML() はスクレイピング対象が Valid でありことが求められる。

HTML エラーが存在するサイトでは機能しない。




IMPORTXML() で取得した値が文字化けしている。

スクレイピングの対象が UTF-8 でないサイトである。

IMPORTXML() は諦めてオリジナルの関数を作成し、getContentText()charset を指定する。



// The code below logs the HTML code of the Google home page with the UTF-8 charset.

var response = UrlFetchApp.fetch("http://www.google.com/");
Logger.log(response.getContentText("UTF-8"));


XmlService.parse() で値が取れない。Parse Error が発生する。

XmlService.parse() も Valid であることが前提なのでパースエラーが起こりやすい。

XmlService.parse() を利用せずに正規表現で値を取得する。



タイトルを取得する例:


Code.js

function getTitle(url) {

var _options = {
method: "GET"
};

try {
var _response = UrlFetchApp.fetch(url, _options);
var _regexp = /<title>(.*?)<\/title>/;
var _title = _response.getContentText().match(_regexp);

return _title[1];
} catch (e) {
return e;
}
}



UrlFetchApp で取得した値に目的のコンテンツが含まれていない。

UrlFetchApp は JavaScript 実行前の HTML が返される。

JavaScript で動的にコンテンツを生成している可能性がある。

curl 等で取得できるソースを確認する。

PhantomJS Cloud のようなサービスと組み合わせる必要がある(著者は利用したことがありません)。



PhantomJsCloud を利用してスクレイピングする例:


Code.js

function getResource(target_url) {

var _options = {
url: target_url,
renderType: "html",
outputAsJson: true
};
var _payload = encodeURIComponent(JSON.stringify(_options));
var _request =
"https://phantomjscloud.com/api/browser/v2/" +
APIKEY +
"/?request=" +
_payload;
var _response = UrlFetchApp.fetch(_request).getContentText();

return _response;
}



補遺


  • スクリプトに実行権限を許可するダイアログでは「詳細」をクリックする。

  • Web エディタ上では JavaScript ES5 を利用する。


    • しっかり書く場合は google/clasp を利用すると良さそう。