puppeteerをcentos7/8に入れて動かす時のポイント
PuppeteerはHeadless ChromeというUIの無いChromeをLinux上で動かして、スクレイピングを行うためのフレームワークである。PhantomJSというフレームワークあり、以前はこちらを使用していたが、スクレイピング性能の面から最近ではPuppeteerを使用している。
具体的にはPhantomJSだとサイトの構造次第では取得したいデータが取れないことがあるが、PuppeteerならChromeで見れるサイトならば確実にデータをぶっこぬくことができる。実際Github上のStar数でもpuppeteerはphantomjsを大きく引き離しており、もはやphantomjsを使う意味は薄いのではないかと思う。
さて、そんな雑談はおいて置き本題に入る。puppeteerが便利であることは間違いないが、HeadLess Chromeをnpm installして動かさなければならない箇所などつまずくポイントも多いので、つまずいたポイントをまとめておく。
Headless Chromeの実行ができない
Headless ChromeをLinuxで動かそうとすると、動かすための共有ファイルが存在しないと言われる。たとえば次のようなエラーが表示される。
(node:5498) UnhandledPromiseRejectionWarning: Error: Failed to launch the browser process!
/home/yamanaka/updatetool/test/node_modules/puppeteer/.local-chromium/linux-800071/chrome-linux/chrome: error while loading shared libraries: libatk-1.0.so.0: cannot open shared object file: No such file or directory
Trouble shootingのページに行くと依存関係がまとめられているので下記のコマンドを叩こう
$ sudo yum install -y alsa-lib.x86_64 atk.x86_64 cups-libs.x86_64 gtk3.x86_64 ipa-gothic-fonts libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXrandr.x86_64 libXScrnSaver.x86_64 libXtst.x86_64 pango.x86_64 xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-fonts-cyrillic xorg-x11-fonts-misc xorg-x11-fonts-Type1 xorg-x11-utils
これで必要なLibraryがすべて揃う。CentOS7ではこの方法で問題なかったが、CentOS8ではこれだけでは足りなかった。しかし案ずることは無く
libatk-1.0.so.0: cannot open shared object file: No such file or directory
などのログを見て、一つずつ足りないものをsudo yum install libatk
などと打って入れていくと何とか動かせるようになるはずである。
sandbox環境で動かせない
sandbox環境とは、OSや他のモジュールに影響を与えることが無いよう誤操作による影響範囲を抑えた仮想的な環境のことであるが、Linuxではsandbox環境を作ることが容易ではない。
defaultでsandbox環境はpuppeteerで有効になっているが、その場合centosでは実行時にエラーとなるので--no-sandbox
オプションを付けて実行してやる必要がある。
chromeのsandbox環境を作成するため、信頼できない不特定のサイトをクローリングする時などはsandbox環境はちゃんと作成しておくべきである。方法はSetting Up Chrome Linux Sandboxを参考
何故か遅くなったら再起動
Puppeteerを実行中、何度もTimeout Errorが起こる場合がある。理由は分からなかったがLinux自体の再起動を掛けてみると上手く動いた。あるいはps aux
で関連するプロセスを殺してやればよかったのかもしれないが原因は不明。
ともあれタイムアウトエラーには再起動が効いたので経験則だが試してほしい。Windowsも調子が悪くなったらとりあえず再起動するっていうことに似た感じである。
最終サンプルコード
最初にサンプルコードを示す。他気を付ける点をまとめておくと
- 多国籍対応のサイトだとlang=jaを設定しないとusのサイトが返ってくることもあるためlang=jaオプションでHTTPヘッダを書き換えておくことが必要な時がある
- UserAgentを判断してボットかどうか等を見分けてコンテンツの表示可否を決定しているサイトがあるため、我々がChromeを使っている時のUserAgentを付与してやる
- 最後きちんとbrowser.close()をしてやること。ブラウザインスタンスが残り続けてLinuxが重くなることがある、finallyで確実にCloseしてやるのが良いだろう。
const puppeteer = require('puppeteer');
let browser;
(async () => {
try {
browser = await puppeteer.launch({
headless: true,
args: [
'--no-sandbox',
'--lang=ja',
]
});
const page = await browser.newPage();
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36');
console.log("goto");
await page.goto('https://yahoo.co.jp', {timeout: 300000});
console.log("done");
console.log("クローリング完了!!!");
} catch (e) {
console.log("クローリング失敗");
console.log(e);
} finally {
await browser.close();
}
})();